Promise原始碼閱讀之ES6 Extensions API
阿新 • • 發佈:2018-12-21
前言
本次閱讀的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執行。