手寫Promise(自定義Promise)

首先我們得先理解Promise工作的機制,其實Promise就是一個構造函數

它的內部有三個狀態

  • pending
  • resolved
  • rejected

而想改變這三個狀態必須要通過resolve()或者reject()這兩個方法,resolve()可以將pending轉換為resolved,rejected()可以將pending轉換為rejected。并且將得到的數值存儲在內部的data里面。并且這狀態一旦轉換是不可逆的。

Promsie的原型對象含有then,catch這兩個方法

  • then這個方法可以接受兩個參數,一個成功的回調,一個失敗的回調。也就是onResolved和onRejected
  • catch這個方法只可以接受一個參數,失敗的回調,也就是onRejected
  • 并且then這個方法,是返回一個新的promise對象,它里面的執行方法也是異步的
  • 觸發then的時候,也會有三個可能,一個是狀態為resolved時,一個是狀態為rejected時,一個是狀態為pending時
  • Promise的結果根據執行的結果返回

然后就可以開始自定義實現Promise了

一、大致框架列出來

  • Promise函數會接受一個構造器,也就是接受一個函數,我們就命名為executor,executor會調用resolve和reject,所以我們就可以寫resolve和reject這兩個方法
  • 定義pending,resolved,rejected。因為后面會多處用到,避免書寫錯誤,導致出現不必要的BUG
  • 內部存儲狀態,和數據,初始狀態為pending,初始值為undefind
  • Promise原型鏈上有then和catch兩個方法
  • Promise函數對象有resolve,reject,all,race方法
(function () {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function Promise(executor){
     this.status = PENDING
     this.data = undefind
     this.callbacks = []
      resolve = () => {
      }
      reject = () => {
      }
      try {
          executor(resolve, reject)
      } catch (e) {
          reject(e)
      }
     Promise.prototype.then = () => {
     }
     Promise.prototype.catch = () => {
     }
      /*Promise函數對象的方法*/
     Promise.resolve = function (value) {

     }
     Promise.reject = function (error) {

     }
    /*只有當所有promise成功時才成功*/
     Promise.all = function (promises) {

     }
    /*其結果由第一個完成的promise決定*/
     Promise.race = function (promises) {
     }
executor(resolve,reject)
}
window.Promise = Promise
})()

二、寫函數內部resolve/reject方法

  • 我們改變promise對象的狀態只能通過resolve/reject改變,所以當我們觸發方法,首先得改變狀態,然后存儲值
  • 我們最開始已經定義了常量,所以直接用定義的值
  • 因為resolve/reject改變狀態只能從pending開始,所以判斷如果狀態不是pending的時候,就不用執行下面代碼了。
resolve = (value) => {
    if(this.satus !== PENDING){
       return
    }
    this.status = RESOLVED
    this.data = value
   if (this.callbacks.length > 0) {
                setTimeout(() => {
                    this.callbacks.forEach(callbacksObj => {
                        callbacksObj.onResolved(value)
                    })
                })
            }
}
reject = (error) => {
    if(this.satus !== PENDING){
       return
    }
    this.status = REJECTED
    this.data = error
   if (this.callbacks.length > 0) {
                setTimeout(() => {
                    this.callbacks.forEach(callbacksObj => {
                        callbacksObj.onRejected(error)
                    })
                })
            }
}

三、重頭戲開始,寫原型對象then方法,Promise的結果根據執行的結果返回

  • 當我們調用then的時候,會傳入兩個回調函數
  • then方法返回的是一個新的promise對象
  • 我們調用then時需要考慮三個結果,也就是當前狀態為pending時,為resolved時,為rejected時
  • then里面所執行的方法是異步的
  • 定義一個公共方法handle,減少代碼冗余性
  • 當我們調用handle函數也要考慮三種情況,因為promise的結果是根據執行的結果返回
Promise.prototype.then = (onResolved,onRejected) => {
   return new Promise((resolve,reject) => {
      function handle(callback){
           /*  
              1、如果拋出異常,return的promise就會失敗
                2、如果回調函數返回的不是promise,return就會成功
                 3、如果回調函數返回的是promise,return的promise結果就是這個promise的結果
           */
            try {
               const result = callback(self.data)
               if (result instanceof Promise) {  //instanceof 運算符用來檢測 Promise.prototype 是否存在于參數 result 的原型鏈
                    result.then(
                          value => {resolve(value)},
                           error => {reject(error)},
                     )
                            //result.then(resolve, reject)
                     } else {
                           resolve(result)
                     }
                     } catch (e) {
                        reject(e)
                     }
      }

      if(this.status === PENDING){
                 this.callbacks.push({
                        onResolved: () => {
                            handle(onResolved)
                        },
                        onRejected: () => {
                            handle(onRejected)
                        }
                    })
      } else if(this.status === RESOLVED){
          setTimeout(() => {
              handle(onRejected)
          })
      } else if(this.status === REJECTED){
          setTimeout(() => {
              handle(onResolved)
          })
      }
   })
}

四、寫原型對象catch方法

 Promise.prototype.catch = function (onRejected) {
            return this.then(undefined,onRejected)
        }
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。