Promise【一】

Promise A+規(guī)范解析

什么是 Promise?

Promise 是用于處理異步操作的一種機(jī)制。它表示一個(gè)異步操作的最終結(jié)果。我們主要通過其 then 方法來與 Promise 進(jìn)行交互,通過注冊回調(diào)函數(shù)來獲取 Promise 的最終值,或者得知為什么 Promise 無法被執(zhí)行的原因。

Promise A+ 規(guī)范的三個(gè)要求

Promise A+ 規(guī)范是 JavaScript 中管理異步操作的一種標(biāo)準(zhǔn),它定義了一個(gè)符合特定要求的 Promise API。以下是 Promise A+ 規(guī)范中的三個(gè)主要要求:

  1. Promise 狀態(tài):

    • Promise 必須處于以下三種狀態(tài)之一:pending(等待態(tài))、fulfilled(完成態(tài))、rejected(拒絕態(tài))。
    • 當(dāng)處于 pending 狀態(tài)時(shí),可以轉(zhuǎn)移到 fulfilled 或 rejected 狀態(tài),但一旦轉(zhuǎn)移到其中一種狀態(tài),就不能再改變狀態(tài)。
  2. then 方法:

    • Promise 對(duì)象必須提供一個(gè) then 方法以訪問其當(dāng)前值、最終值或拒絕原因。
    • then 方法接受兩個(gè)參數(shù):onFulfilledonRejected,分別是當(dāng) Promise 狀態(tài)變?yōu)?fulfilled 或 rejected 時(shí)執(zhí)行的回調(diào)函數(shù)。
    • then 方法必須返回一個(gè)新的 Promise 對(duì)象。
  3. Promise 解決程序:

    • Promise 解決程序是 Promise A+ 規(guī)范的核心算法,它定義了 Promise 對(duì)象如何處理異步操作和狀態(tài)轉(zhuǎn)換。
    • 在 Promise 解決程序中,如果一個(gè) Promise 對(duì)象被 resolved(fulfilled 或 rejected),則必須按照特定的順序執(zhí)行相應(yīng)的回調(diào)函數(shù)隊(duì)列。
    • Promise 解決程序確保異步操作的結(jié)果能夠正確傳遞給相應(yīng)的回調(diào)函數(shù),并且保持了回調(diào)函數(shù)的執(zhí)行順序。

遵循這三個(gè)要求可以確保 Promise 對(duì)象的行為符合預(yù)期,并且能夠正確處理異步操作。

ES6 的 Promise 實(shí)現(xiàn)遵循了 Promise A+ 規(guī)范。


ES6 Promise 源碼解析

源碼地址

Promise
function Promise(fn) {
  // 判斷是否通過 new 關(guān)鍵字調(diào)用該函數(shù)
  if (typeof this !== 'object') {
    throw new TypeError('Promises must be constructed via new');
  }
  // 判斷傳入的參數(shù)是否為函數(shù)
  if (typeof fn !== 'function') {
    throw new TypeError('Promise constructor\'s argument is not a function');
  }
  // 在代碼中定義了多個(gè)成員變量,這些變量均以下劃線 "_" 開頭,并且在構(gòu)建時(shí)會(huì)被簡化為 _{隨機(jī)數(shù)} 的格式,以達(dá)到混淆和不鼓勵(lì)直接訪問的目的。
  // 選擇這種方式而不是使用 Symbol 或 Object.defineProperty 完全隱藏它們,是出于性能方面的考慮,因?yàn)橥耆[藏可能會(huì)對(duì)性能產(chǎn)生影響。

  // _deferreds個(gè)數(shù)標(biāo)識(shí),0為0個(gè),1為一個(gè),2為多個(gè)。
  this._deferredState = 0;
  // _state有0、1、2、3四個(gè)值。
  // 0 代表pending(等待態(tài))
  // 1 代表fulfilled(完成態(tài))
  // 2 代表 rejected(拒絕態(tài))
  // 3 代表采用了另外一個(gè)promise的狀態(tài)
  this._state = 0;
  // 結(jié)果值
  this._value = null;
  // 采用了該promise狀態(tài)的promise數(shù)組
  this._deferreds = null;
  // 在then方法中,會(huì)產(chǎn)生一個(gè)新的Promise對(duì)象,但新產(chǎn)生的對(duì)象不需要執(zhí)行fn,即不需要做doResolve,這里判斷直接返回即可。
  if (fn === noop) return;
  doResolve(fn, this);
}

Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;

// then 方法,上文提到的Promise A+規(guī)范的三個(gè)要求之一
Promise.prototype.then = function(onFulfilled, onRejected) {
  // 調(diào)用對(duì)象判斷,如通過Promise.prototype.then.call(otherPromise, callback)等方式調(diào)用,需做安全調(diào)用處理。
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  // 創(chuàng)建一個(gè)新的Promise對(duì)象,#重點(diǎn)#then或catch都會(huì)產(chǎn)生一個(gè)新的Promise對(duì)象。
  var res = new Promise(noop);
  handle(this, new Handler(onFulfilled, onRejected, res));
  // #重點(diǎn)# 每調(diào)用一次then返回,返回的是一個(gè)新的Promise實(shí)例。
  return res;
};
safeThen
// 如上所述,每次調(diào)用 then 方法都會(huì)返回一個(gè)新的 Promise 對(duì)象。
// 然而,在按照 Promise A+ 規(guī)范實(shí)現(xiàn)的 Promise 中,直接返回 ES6 Promise 的實(shí)例是不合理的。
// 因此需要采取以下處理措施:
function safeThen(self, onFulfilled, onRejected) {
  // 通過其構(gòu)造器生成一個(gè)新對(duì)象
  return new self.constructor(function (resolve, reject) {
    // 生成一個(gè)ES6 Promise對(duì)象
    var res = new Promise(noop);
    // then后調(diào)用回調(diào)
    res.then(resolve, reject);
    handle(self, new Handler(onFulfilled, onRejected, res));
  });
}
doResolve
function doResolve(fn, promise) {
  // `done`標(biāo)識(shí),確保onFulfilled(完成態(tài)回調(diào))和onRejected(拒絕態(tài)回調(diào))只會(huì)被調(diào)用一次
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    if (done) return;
    done = true;
    resolve(promise, value);
  }, function (reason) {
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  // 當(dāng)`done`為`false`,并且發(fā)生異常時(shí),執(zhí)行`reject`。
  // 這種情況發(fā)生在Promise的入?yún)fn`在執(zhí)行的時(shí)候發(fā)生異常。
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}
resolve
function resolve(self, newValue) {
  // 邊界場景處理,promise不能resolve自身。
  if (newValue === self) {
    return reject(
      self,
      new TypeError('A promise cannot be resolved with itself.')
    );
  }
  // 如果newValue是一個(gè)對(duì)象或者函數(shù),需判斷其是否包含then方法。
  if (
    newValue &&
    (typeof newValue === 'object' || typeof newValue === 'function')
  ) {
    var then = getThen(newValue);
    // 訪問then方法異常處理
    if (then === IS_ERROR) {
      return reject(self, LAST_ERROR);
    }
    // 同根生的then時(shí),且new Value為ES6 Promise對(duì)象時(shí)
    if (
      then === self.then &&
      newValue instanceof Promise
    ) {
      // 跟隨狀態(tài)(俺也一樣)
      self._state = 3;
      // 新值賦給_value
      self._value = newValue;
      finale(self);
      return;
    } else if (typeof then === 'function') {
      // 如果有then方法,從新執(zhí)行doResolve(不過是從頭再來)
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  // 狀態(tài)變?yōu)橥瓿蓱B(tài),newValue賦值給_value
  self._state = 1;
  self._value = newValue;
  finale(self);
}

function reject(self, newValue) {
  // 狀態(tài)改為拒絕態(tài),newValue賦值給_value
  self._state = 2;
  self._value = newValue;
  if (Promise._onReject) {
    Promise._onReject(self, newValue);
  }
  finale(self);
}
function finale(self) {
  // 調(diào)用handle,根據(jù)_deferredState判斷_deferreds的個(gè)數(shù),采用直接或遍歷的調(diào)用方式,調(diào)用完清空_deferreds
  if (self._deferredState === 1) {
    handle(self, self._deferreds);
    self._deferreds = null;
  }
  if (self._deferredState === 2) {
    for (var i = 0; i < self._deferreds.length; i++) {
      handle(self, self._deferreds[i]);
    }
    self._deferreds = null;
  }
}
handle
function handle(self, deferred) {
  // 找到_state不等于3的promise(who is your daddy)
  while (self._state === 3) {
    self = self._value;
  }
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  // 當(dāng)當(dāng)前對(duì)象是pending狀態(tài),將deferred賦值給對(duì)象的_deferreds。如果是多個(gè)deferred,則已數(shù)組元素的方式追加到_deferreds后。
  if (self._state === 0) {
    if (self._deferredState === 0) {
      self._deferredState = 1;
      self._deferreds = deferred;
      return;
    }
    if (self._deferredState === 1) {
      self._deferredState = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    self._deferreds.push(deferred);
    return;
  }
  handleResolved(self, deferred);
}

function handleResolved(self, deferred) {
  // aspa[https://github.com/kriskowal/asap],不展開說,簡單理解就是微任務(wù)。
  asap(function() {
    // 根據(jù)狀態(tài)判斷需要執(zhí)行的回調(diào)
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    // 沒有回調(diào)的情況
    if (cb === null) {
      if (self._state === 1) {
        resolve(deferred.promise, self._value);
      } else {
        reject(deferred.promise, self._value);
      }
      return;
    }
    // 執(zhí)行回調(diào)
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
}

// Hanlder對(duì)象
function Handler(onFulfilled, onRejected, promise){
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}
getThen tryCallOne tryCallTow

這幾個(gè)函數(shù)是為了避免在關(guān)鍵函數(shù)中使用try/catch,把它們都提取到這里。

// 記錄最后一次異常
var LAST_ERROR = null;
// 異常標(biāo)識(shí),使用`{}`作為值的作用類似于`Symbol`
var IS_ERROR = {};
function getThen(obj) {
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

以上是對(duì)Promise core.js的解析。后面會(huì)解析ES6 Promise的其它特性的實(shí)現(xiàn)。

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

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

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