1. 程式人生 > >Promise原始碼閱讀之ES6 Extensions API

Promise原始碼閱讀之ES6 Extensions API

前言

本次閱讀的Promise是基於Promise A+規範的,對於ES6 Promises規範中有些API需要提供另外的支援,即ex6-extensions.js檔案中的邏輯處理。本篇文章就將Promise庫實現的ES6 Promises規範中定義的相關API。

實際上就是下面幾個API:

  • Promise.resolve()
  • Promise.reject()
  • Promise.all()
  • Promise.race()
  • Promise.prototype.catch

具體分析

Promise.resolve

該方法返回一個fulfilled狀態的Promise物件

  if (value instanceof
Promise) return value; // NULL 即valuePromise(null) if (value === null) return NULL; // 與NULL同理 if (value === undefined) return UNDEFINED; if (value === true) return TRUE; if (value === false) return FALSE; if (value === 0) return ZERO; if (value === '') return EMPTYSTRING; if (typeof value ===
'object' || typeof value === 'function') { // 處理是否存在then函式 } return valuePromise(value);

而valuePromise實際上就是返回一個Promise物件,即:

function valuePromise(value) {
  var p = new Promise(Promise._n);
  // 狀態
  p._i = 1;
  p._j = value;
  return p;
}

Promise.resolve()總是返回狀態為fulfilled的promise物件

Promise.reject

而對於Promise.reject就是支援建立Promise並呼叫reject函式,即:

Promise.reject = function (value) {
  return new Promise(function (resolve, reject) {
    reject(value);
  });
};

Promise.all

Promise.all是用於處理非關聯的多個請求情況下的首選處理方式,而all方法背後的實現上還是遍歷來實現每個Promise相關函式的處理,核心處理邏輯如下:

Promise.all = function() {
  var args = Array.prototype.slice.call(arr);

  return new Promise(function (resolve, reject) {
    if (args.length === 0) return resolve([]);
    var remaining = args.length;
    function res(i, val) {
      // 判斷val是否是物件或函式,進行相關處理
      args[i] = val;
      // 只有所有的引數結果都獲取到了才會主動觸發resolve
      if (--remaining === 0) {
        resolve(args);
      }
    }
    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

上面邏輯中res中有對於val為函式或物件的處理邏輯,而實際上的處理邏輯如下:

if (val && (typeof val === 'object' || typeof val === 'function')) {
        if (val instanceof Promise && val.then === Promise.prototype.then) {
          while (val._i === 3) {
            val = val._j;
          }
          if (val._i === 1) return res(i, val._j);
          if (val._i === 2) reject(val._j);
          // 主要處理狀態0和2情況
          val.then(function (val) {
            res(i, val);
          }, reject);
          return;
        } else {
          var then = val.then;
          if (typeof then === 'function') {
            var p = new Promise(then.bind(val));
            p.then(function (val) {
              res(i, val);
            }, reject);
            return;
          }
        }
      }

上面的處理邏輯總結如下:

  • 首先判斷val是否是物件或函式
  • 如果val是物件並且存在then函式
  • 如果當前Promise狀態為3即val是另一個Promise物件,則會執行邏輯死迴圈一直等待其狀態改變
  • 當前Promise狀態修改為0、1或2,即表示執行完畢,1則是成功,2則是發生異常,0表示初始化狀態
  • 再對val表示的Promise物件的執行結果進行判斷重複性的判斷,直至val不存在then函式
  • 如果val不是物件或者val是物件但不存在then函式,則會進行另外的判斷
  • 判斷val是否存在then函式,是則建立Promise,則呼叫bind函式執行當前then的this值,作為新的回撥處理

Promise.race


Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      // 只要有一個value執行完就會觸發resolve
      Promise.resolve(value).then(resolve, reject);
    });
  });
};

Promise.catch

catch方法實際上就是then(null, reject),即:

Promise.prototype['catch'] = function (onRejected) {
  return this.then(null, onRejected);
};

總結

整體介紹了promise對於ES6 Promises API的實現支援,實際上這裡想要提及下promise中使用的asap,asap實際上底層使用的還是瀏覽器提供的非同步操作API。

對於Node.js環境,使用setImmediate或process.nextTick來實現callback執行 對於瀏覽器環境,使用MutationObserver 或 setTimeout、setIntervel來實現callback執行。