簡單實現(xiàn) ES6 Promise

最近在使用ES6,所以手動實現(xiàn)了一個簡單的ES6 Promise對象來玩玩(如果有錯誤的地方,希望大家能夠不吝賜教)

一個promise對象接收的是一個callback
這個callback接收兩個參數(shù)(resolve,reject)
當(dāng)我們在callback內(nèi)執(zhí)行resolvereject的時候,就會調(diào)用Promise內(nèi)定義的 resolvereject函數(shù)
然后,resolvereject函數(shù)會改變Promise的狀態(tài)
所以它應(yīng)該是像下面這樣的

function MyPromise(callback) {
  // 保存this值
  var self = this
  // 記錄狀態(tài)null為pending,true為resolved,false為reject
  var state = null
  // 記錄resolve的參數(shù)
  var param = null

  // 執(zhí)行傳入的callback并改變promise對象狀態(tài)
  callback(resolve, reject)
  // resolve方法
  function resolve(data) {
    // 改變狀態(tài)
    state = true
    param = data
  }

  // reject方法
  function reject(err) {
    state = false
    param = err
  }
}

但沒有then方法的Promise對象是不完整的(完全沒有用)
所以我們需要一個then方法,要記住then方法返回的也是一個promise對象
then方法接收兩個可選的參數(shù)(onFulfilled, onRejected)(我們可以先忽略可選兩個字)
then方法傳進(jìn)來的參數(shù)必須是函數(shù),如果不是就要忽略(PromiseA+規(guī)范)(我們可以也先忽略這句話)

  this.then = function (onFulfilled, onRejected) {
    // 返回一個新的promise對象
    return new self.constructor(function (resolve, reject) {
      // then
    })
  }

接下來就是then方法的具體實現(xiàn)了
then方法中onFulfilled, onRejected的返回值會作為新promise的執(zhí)行結(jié)果

onFulfilled, onRejected這兩個函數(shù)要在promise的狀態(tài)變?yōu)閜ending或resolved的時候才能分別執(zhí)行
所以如果promise方法狀態(tài)為resolvedrejected的話,我們就可以直接在then方法中執(zhí)行resolve(onFulfilled(param))reject(onRejected(param))

  this.then = function (onFulfilled, onRejected) {
    // 返回一個新的promise對象
    return new self.constructor(function (resolve, reject) {
       if (state === true) {
        // param是promise對象完成后的結(jié)果
        resolve(onFulfilled(param))
      } else if (state === false) {
        reject(onRejected(param))
      } else {
        // 沒有執(zhí)行完畢,怎么辦
      }
    })
  }

但如果promise的狀態(tài)為pending
由于原始promise的狀態(tài)我們是無法動態(tài)獲取的,因此我們就需要在他執(zhí)行狀態(tài)改變的時候同時執(zhí)行onFulfilledonRejected方法
我們可以把這個方法放在原始promise對象的resolvereject方法中執(zhí)行
因此我們要在promise的對象定義中添加四個參數(shù),分別記錄onFulfilledonRejected,以及then方法返回的新promise對象的resolvereject
然后如果執(zhí)行then方法的時候promise對象的狀態(tài)為pending的話,就將上述四個參數(shù)記錄起來

// then方法返回的promise對象的resolve和reject
var nextResolve = null
var nextReject = null
// 記錄then方法的參數(shù),onFulfilled和onRejected
var asynconFulfilled = null
var asynconRejected = null

//then方法
this.then = function (onFulfilled, onRejected) {
    // 返回一個新的promise對象
    return new self.constructor(function (resolve, reject) {
      if (state === true) {
        // param是promise對象完成后的結(jié)果
        resolve(onFulfilled(param))
      } else if (state === false) {
        reject(onRejected(param))
      } else {
        nextResolve = resolve
        nextReject = reject
        asynconFulfilled = onFulfilled
        asynconRejected = onRejected
      }
    })
  }

接下來就是原始promise中的resolvereject的重新實現(xiàn)

 // resolve方法
  function resolve(data) {
    // 改變狀態(tài)
    state = true
    param = data
    nextResolve(asynconFulfilled(param))
  }

  // reject方法
  function reject(err) {
    state = false
    param = err
    nextReject(asynconRejected(param))
  }

很簡單不是嗎
我們繼續(xù)
上述實現(xiàn)我們一直沒有考慮一個很重要的情況,如果then方法返回的還是一個promise對象,那么如果我們后邊還有then方法的話就要等待前一個then方法中的promise對象的狀態(tài)從pending變?yōu)橥瓿?br> 這要怎么做呢
什么時候可以認(rèn)為then方法返回的promise對象執(zhí)行完畢了呢,這里我們就要用到then方法(@_@,邊寫邊用...),
resolve方法為例

var self = this
// resolve方法
function resolve(data) {
  // 記錄onFulfilled的執(zhí)行結(jié)果
  let parmise
  // 改變狀態(tài)
  state = true
  param = data
  // 執(zhí)行記錄的onFulfilled
  parmise = asynconFulfilled(param)
  if(parmise === undefined){
    // 如果parmise為undefined,就不能解析parmise.constructor
  } else if (parmise.constructor === self.constructor) {
    // 等待傳遞進(jìn)來的promise對象執(zhí)行完畢,然后根據(jù)傳遞進(jìn)來的promise對象的狀態(tài)執(zhí)行resolve或reject
    // 注意,這個param是形參,在then方法的promise中執(zhí)行
    promise.then(function (param) {
      resolve(param)
    }, function (param) {
      reject(param)
    })
  } else {
    // 這個是前邊的then返回的不是promise對象的情況
    resolve(promise)
  }
}

前面我們忽略了兩點 (then方法接收兩個可選的參數(shù)(onFulfilled, onRejected)) 和 (then方法傳進(jìn)來的參數(shù)必須是函數(shù),如果不是就要忽略)

var self = this
// resolve方法
function resolve(data) {
  // 記錄onFulfilled的執(zhí)行結(jié)果
  var parmise
  // 改變狀態(tài)
  state = true
  param = data
  // 執(zhí)行記錄的onFulfilled
  // begin--------------
  if (typeof onFulfilled === 'function') {
    promise = onFulfilled(param)
    if (promise === undefined) {
      // 待補充
    } else if (promise.constructor === self.constructor) {
      // 注意,這個param是形參,在then方法的promise中執(zhí)行
      promise.then(function (param) {
        resolve(param)
      }, function (param) {
        reject(param)
      })
    } else {
      reject(promise)
    }
  } else {
    // 如果onFulfilled不是function,忽略,直接resolve或reject
    resolve(param)
  }
  // ---------------end
}

上面begin到end之間的代碼還要在then方法調(diào)用,所以我們可以把這段代碼抽象為一個函數(shù)
resolvereject的原理相同,只要注意如果不是function 的話需要執(zhí)行reject


onFulfilledonRejected只有在[執(zhí)行環(huán)境]堆棧僅包含平臺代碼時才可被調(diào)用
所以將上述begin-end之間的代碼放到seTimeout中執(zhí)行(瀏覽器環(huán)境)

function resolve(data) {
  // 記錄onFulfilled的執(zhí)行結(jié)果
  var parmise
  // 改變狀態(tài)
  state = true
  param = data
  // 執(zhí)行記錄的onFulfilled
  window.setTimeout(function () {
    // begin--------------
    // 上述代碼
    // ---------------end
  }, 0)
}

下面是完整代碼

// 簡單實現(xiàn)ES6 Promise
function MyPromise(callback) {
  // 保存this值
  var self = this
  // 記錄狀態(tài)null為pending,true為resolved,false為reject
  var state = null
  // 記錄resolve的參數(shù)
  var param = null
  // then方法返回的promise對象的resolve和reject
  var nextResolve = null
  var nextReject = null
  // 記錄then方法的參數(shù),onFulfilled和onRejected
  var asynconFulfilled = null
  var asynconRejected = null

  // 執(zhí)行并改變promise對象狀態(tài)
  callback(resolve, reject)
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 返回一個新的promise對象
    return new self.constructor(function (resolve, reject) {
      // 判斷異步代碼是否執(zhí)行完畢(是否resolve或reject)
      // 若執(zhí)行完畢就在then方法中立即執(zhí)行,否則將四個參數(shù)記錄下來,等待state就緒后再執(zhí)行doAsyn*函數(shù)
      if (state === true) {
        doAsynconFulfilled(onFulfilled, resolve, reject)
      } else if (state === false) {
        doAsynconRejected(onRejected, resolve, reject)
      } else {
        nextResolve = resolve
        nextReject = reject
        asynconFulfilled = onFulfilled
        asynconRejected = onRejected
      }
    })
  }
  // resolve方法
  function resolve(data) {
    // 改變狀態(tài)
    state = true
    param = data
    if(nextResolve){
        doAsynconFulfilled(asynconFulfilled, nextResolve, nextReject)
    }
  }

  // reject方法
  function reject(err) {
    state = false
    param = err
    if(nextReject){
        doAsynconRejected(asynconRejected, nextResolve, nextReject)
    }
  }

  // 核心方法(我覺得是)

  function doAsynconFulfilled(onFulfilled, resolve, reject) {
      window.setTimeout(function () {
        // 判斷onFulfilled是否為function,不是則忽略
        if (typeof onFulfilled === 'function') {
          // 執(zhí)行onFulfilled方法獲取返回值promise()
          let promise = onFulfilled(param)
          // 如果promise為undefined 執(zhí)行 if
          // 如果promise為MyPromise對象 執(zhí)行 else if
          // 如果promise為非MyPromise對象 執(zhí)行 else
          if (promise === undefined) {
            resolve(param)
            // 待補充
          } else if (promise.constructor === self.constructor) {
            // 等待傳遞進(jìn)來的promise對象執(zhí)行完畢,然后根據(jù)傳遞進(jìn)來的promise對象的狀態(tài)執(zhí)行resolve或reject
            promise.then(function (param) {
              resolve(param)
            }, function (param) {
              reject(param)
            })
          } else {
            // 執(zhí)行then方法返回的對象的resolve
            resolve(promise)
          }
        } else {
          // 傳遞參數(shù)
          resolve(param)
        }
      }, 0)
    
  }

  function doAsynconRejected(onRejected, resolve, reject) {
    window.setTimeout(function () {
        if (typeof onRejected === 'function') {
          let promise = onRejected(param)
          if (promise === undefined) {
            reject(param)
            // 待補充
          } else if (promise.constructor === self.constructor) {
            promise.then(function (param) {
              resolve(param)
            }, function (param) {
              reject(param)
            })
          } else {
            reject(promise)
          }
        } else {
          // 傳遞錯誤信息
          reject(param)
        }
    }, 0)
  }
}
// 測試使用
var b = function (message) {
    return new MyPromise(function (resolve, reject) {
        document.body.onclick = function () {
            resolve('click:' + message)
        }
    })
}
var a = new MyPromise(function (resolve, reject) {
  resolve(123)
}).then(function (message) {
    return b(message)
}).then().then(function (message) {
    console.log('final:' + message)
},function (err) {
    console.log('final:' + err)
})
console.log('window')

完畢!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文適用的讀者 本文寫給有一定Promise使用經(jīng)驗的人,如果你還沒有使用過Promise,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,444評論 6 19
  • Promiese 簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果,語法上說,Pr...
    雨飛飛雨閱讀 3,484評論 0 19
  • Promise的含義: ??Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,262評論 0 16
  • 00、前言Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。它由社區(qū)...
    夜幕小草閱讀 2,217評論 0 12
  • 特點 Promise能將回調(diào)分離出來,在異步操作執(zhí)行之后,用鏈?zhǔn)椒椒▓?zhí)行回調(diào),雖然es5用封裝函數(shù)也能實現(xiàn),但是如...
    一二三kkxx閱讀 714評論 0 1

友情鏈接更多精彩內(nèi)容