手擼 Promise (then、catch)

張大D?發表於2018-12-12

最近也處於校招面試當中,當然也少不了對 Promise 的話題了。開啟 MDN,對著 Promise 的方法,把 then 和 catch 擼了出來。

developer.mozilla.org/zh-CN/docs/… 這是 MDN 中對 Promise 的詳細介紹。

屬性

function myPromise(executor) {
  const self = this

  self.status = 'pending'
  self.value = undefined

  self.onResolvedCallbacks = []
  self.onRejectedCallbacks = []

  function resolve(value) {
    if (self.status === 'pending') {
      self.status = 'fulfilled'
      self.value = value
      self.onResolvedCallbacks.forEach(fn => fn(self.value))
    }
  }

  function reject(error) {
    if (self.status === 'pending') {
      self.status = 'rejected'
      self.value = error
      self.onResolvedCallbacks.forEach(fn => fn(self.value))
    }
  }

  try {
    executor(resolve, reject)
  } catch (error) {
    reject(error)
  }
}
複製程式碼

我們看到 MDN 中對 executor 的介紹:

executor 是帶有 resolve 和 reject 兩個引數的函式,Promise建構函式執行時立即呼叫executor 函式。

resolve 和 reject 函式被呼叫時,分別將promise的狀態改為fulfilled(完成)或rejected(失敗)

executor 內部通常會執行一些非同步操作,一旦完成,可以呼叫resolve函式來將promise狀態改成fulfilled,或者在發生錯誤時將它的狀態改為rejected。

then

myPromise.prototype.then = function (onFulfilled, onRejected) {
  // then 傳入的引數不是 function,要忽略它
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {
    throw reason
  }

  const self = this

  if (self.status === 'fulfilled') {
    return new myPromise((resolve, reject) => {
      try {
        let x = onFulfilled(self.value)
        if (x instanceof myPromise) {
          x.then(resolve, reject)
        }
        resolve(x)
      } catch (e) {
        reject(e)
      }      
    })
  }

  if (self.status === 'rejected') {
    return new myPromise((resolve, reject) => {
      try {
        let x = onRejected(self.value)
        if (x instanceof myPromise) {
          x.then(resolve, reject)
        }
        resolve(x)
      } catch (e) {
        reject(e)
      }
    })
  }

  // 非同步
  if (self.status === 'pending') {
    return new myPromise((resolve, reject) => {
      self.onResolvedCallbacks.push((value) => {
        try {
          let x = onFulfilled(value)
          if (x instanceof myPromise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
       
      self.onRejectedCallbacks.push((value) => {
        try {
          let x = onRejected(value)
	  if (x instanceof myPromise) {
            x.then(resolve, reject)
          }
	  resolve(x)
        } catch (e) {
	  reject(e)
        }
      })
    })
  }
}
複製程式碼

MDN 中 then 的解釋:

新增解決(fulfillment)和拒絕(rejection)回撥到當前 promise, 返回一個新的 promise, 將以回撥的返回值來resolve.

catch

myPromise.prototype.catch = function (onRejected) {
  // then 傳入的引數不是 function,要忽略它
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {
    throw reason
  }

  const self = this

  if (self.status === 'fulfilled') {
    return new myPromise((resolve, reject) => {
      try {
        resolve(self.value)
      } catch (e) {
        reject(e)
      }
    })
  }

  if (self.status === 'rejected') {
    return new myPromise((resolve, reject) => {
      try {
        let x = onRejected(self.value)
        if (x instanceof myPromise) {
          x.then(resolve, reject)
        }
	resolve(x)
      } catch (e) {
        reject(e)
      }
    })
  }

  // 非同步
  if (self.status === 'pending') {
    return new myPromise((resolve, reject) => {
      self.onRejectedCallbacks.push((value) => {
        try {
          let x = onRejected(value)
          if (x instanceof myPromise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
    })
  }
}
複製程式碼

MDN 中 catch 的解釋:

新增一個拒絕(rejection) 回撥到當前 promise, 返回一個新的promise。當這個回撥函式被呼叫,新 promise 將以它的返回值來resolve,否則如果當前promise 進入fulfilled狀態,則以當前promise的完成結果作為新promise的完成結果.

相關文章