Promise 原始碼:靜態方法

cobish發表於2019-03-01

前言

最後來看一下 Promise 的幾個常用的靜態方法的實現:

  • Promise.resolve
  • Promise.reject
  • Promise.all
  • Promise.race

注:本次閱讀的是 then/promise 的 4.0.0 版本,原始碼請戳 這裡

解讀

在 4.0.0 版本之中,Promise 物件被封裝在了 core.js 檔案中,常用的靜態方法則寫在了 index.js 檔案中,開啟 index.js 檔案。

Promise.resolve

Promise.resolve 方法有下面三種使用形式:

Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(theanable);
複製程式碼

這三種形式都會產生一個新的 Proimse,從而能夠繼續 then 鏈式呼叫。

Promise.resolve = function (value) {
  return new Promise(function (resolve) { 
    resolve(value);
  });
}
複製程式碼

Promise.resolve 的實現,就是 new 一個新的 Promise 例項並呼叫 resolve 方法,最後返回。

Promise.reject

Promise.reject 與 Promise.resolve 同理,只不過將 resolve 替換成 reject。

Promise.reject = function (value) {
  return new Promise(function (resolve, reject) { 
    reject(value);
  });
}
複製程式碼

Promise.all

Promise.all 可以將傳入的多個 Promise 例項裡都 resolve 成功再返回一個結果陣列。

實現的思路就是用一個計數器,從零開始計,每當一個 Promise 例項呼叫了 resolve,則 +1。知道計數器等於 Promise 例項的數量時,表示全部都執行完了,此時返回結果。

Promise.all = function () {
  var args = Array.prototype.slice.call(arguments.length === 1 && Array.isArray(arguments[0]) ? arguments[0] : arguments)

  return new Promise(function (resolve, reject) {
    if (args.length === 0) return resolve([])
    var remaining = args.length
    function res(i, val) {
      try {
        if (val && (typeof val === `object` || typeof val === `function`)) {
          var then = val.then
          if (typeof then === `function`) {
            then.call(val, function (val) { res(i, val) }, reject)
            return
          }
        }
        args[i] = val
        if (--remaining === 0) {
          resolve(args);
        }
      } catch (ex) {
        reject(ex)
      }
    }
    for (var i = 0; i < args.length; i++) {
      res(i, args[i])
    }
  })
}
複製程式碼

實現的程式碼裡是做減法,跟計數器做加法思路是一致的。程式碼裡 new 了一個新的 Promise,當觸發了計數器設定的值(即 0),則呼叫它的 resolve,從而觸發 then 函式。

res 函式裡,給每一個 Promise 例項繫結一個 then 方法,當觸發 resolve,即觸發 then,從而再次呼叫 res 函式。只有傳入的值不再是 Promise 例項,此時就用 args 記錄,作為以後返回的結果陣列。並重新設定計數器 remaining(做減法)。

remaining 被減到了 0,表示所有傳入的 Promise 例項都執行了 resolve,此時可以呼叫新 new 出來的 Promise 例項的 resolve 。

Promise.race

Promise.race 與 Promise.all 相反,只要傳入的多個 Promise 例項只要有一個呼叫了 resolve 就會觸發它的 then 函式。

原始碼是這樣的:

Promise.race = function (values) {
  return new Promise(function (resolve, reject) { 
    values.map(function(value){
      Promise.cast(value).then(resolve, reject);
    })
  });
}
複製程式碼

程式碼裡也 new 了一個新的 Promise 例項,給傳入的每一個 Promise 例項也都繫結 then 方法。只要有一個 Promise 執行了 then,就直接執行了 resolve。

這裡的 Promise.cast 方法是為了返回一個可以呼叫 then 的 Promise 例項。

這裡可以看最新的 原始碼實現 更好理解:

Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      Promise.resolve(value).then(resolve, reject);
    });
  });
};
複製程式碼

最後

看了 Promise 的靜態方法原始碼,會發現都是基於之前的一整套 Promise 物件來實現的,沒有新的知識點。看起來不好實現的程式碼,卻是這樣幾行程式碼就實現了,是我想複雜了。

不經感慨,芸芸眾生,活到老,學到老啊。

相關文章