什么是Promise?
MDN檔案對Promise的解釋是: Promise 物件用于表示一個異步操作的最終完成 (或失敗)及其結果值,
民間也有一種說法是: Promise是優雅解決異步回呼函式嵌套地獄問題的一種解決方案,
下面是我個人對Promise的一個通俗的解釋:
什么是Promise/A+? 它跟ECMAScript 6的Promise又是什么關系?
- Promise/A+是Promise的一個開放的標準或者是規范,它規范了Promise的術語和要求(包括Promise的三種狀態、必須提供一個then方法和Promise的解決流程),
- ECMAScript 6里面的Promise是Promise/A+規范的一種實作方案,它是一個規范的具體的一種實作方案,它在原有的Promise/A+規定上擴展了一些API:
Promise.prototype.catch()
Promise.prototype.finally()
Promise.allSettled()
Promise.all()
Promise.race()
Promise.any()
Promise.reject()
Promise.resolve()
下面是用圖來形容它們之間的關系

來看看Promise流程圖:

下面是一個實作了Promsoe/A+規范同時也擴展了ECMAScript6的PromiseAPI的原始碼并且含有大量注釋,(通過了所有promises-aplus-test的測驗案例)

如果你也想測驗你自己撰寫的Promsie是否符合**Promise/A+**規范可以下載一個 “promises-aplus-test” 的工具來測驗,下面是安裝命令:
npm install promises-aplus-tests -g
下面是promises-aplus-test的用法:
Promise.deferred = function() {
const deferred = {}
deferred.promise = new Promise((resolve, reject) => {
deferred.resolve = resolve
deferred.reject = reject
})
return deferred
}
module.exports = Promise;
在你撰寫的promise檔案的末尾添加這些代碼然后在命令列運行下面命令就可以
promises-aplus-tests 你要測驗的檔案名.js
下面是我撰寫的Promise原始碼
const PEDDING = "pending",
FULFILLED = "fulfilled",
REJECTED = "rejected";
function isPromise(val) {
return (
val !== undefined &&
val !== null &&
(typeof val === 'object' || typeof val === 'function') &&
typeof val.then === 'function'
);
}
/**
* @todo The Promise Resolution Procedure=>Promise的解決流程
* @description Promise/A+ 規范
* 的承諾解決程序是一個抽象的操作作為輸入一個承諾和一個值,它表示我們作為[[Resolve]](promise, x),如果x是可能的,則在行為至少類似于承諾的假設下,
* 嘗試promise采用的狀態,否則,它將滿足value ,xxpromisex只要對約定的實作公開Promises / A +兼容的then方法,對約定的實作就可以進行互操作,
* 它還允許Promises / A +實作以合理的then方法“同化”不合格的實作,
要運行[[Resolve]](promise, x),請執行以下步驟:
2.3.1 如果promise和x參考相同的物件,promise則以拒絕TypeError為理由,
2.3.2 如果x是一個承諾,則采用其狀態[ 3.4 ]:
2.3.2.1 如果x未決,則promise必須保持未決狀態,直到x實作或被拒絕,
2.3.2.2 如果/何時x滿足,promise則以相同的值滿足,
2.3.2.3 如果/何時x被拒絕,promise則以相同的理由拒絕,
2.3.3 否則,如果x是物件或函式,
2.3.3.1 我們then是x.then,[ 3.5 ]
2.3.3.2 如果檢索屬性x.then中拋出的例外的結果e,拒絕promise與e作為的原因,
2.3.3.3 如果then是函式,請使用xas this,第一個引數resolvePromise和第二個引數進行呼叫rejectPromise,其中:
2.3.3.3.1 如果/何時resolvePromise使用值呼叫y,請運行[[Resolve]](promise, y),
2.3.3.3.2 如果/當rejectPromise是帶一個理由r,拒絕promise與r,
2.3.3.3.3 如果同時呼叫resolvePromise和rejectPromise,或者對同一引數進行了多次呼叫,則第一個呼叫優先,而所有其他呼叫均被忽略,
2.3.3.3.4 如果呼叫then引發例外e,
2.3.3..3.4.1 如果resolvePromise或rejectPromise已經被呼叫,則忽略它,
2.3.3..3.4.2 否則,拒絕promise與e作為的原因,
2.3.3.4 如果then不是一個函式,實作promise用x,
2.3.4 如果x不是一個物件或功能,實作promise與x,
如果使用參與回圈的可回圈鏈的可轉換組件來解決承諾,從而[[Resolve]](promise, thenable)最終導致遞回性質[[Resolve]](promise, thenable)被再次呼叫,
則遵循上述演算法將導致無限遞回,鼓勵但不是必需的實作,以檢測這種遞回并promise以提供資訊TypeError為理由的拒絕,[ 3.6 ]
* @param {Promise} promise2
* @param {*} x
* @param {Function} resolve
* @param {Function} reject
* @returns {void}
*/
function resolvePromise(promise2, x, resolve, reject) {
//如果promise和x參考相同的物件,promise則以拒絕TypeError為理由,
/**
* 例子:
* const p=new Promise((resolve,reject)=>{
* resolve(xxx);
* }).then(v=>{
* return p;
* })
*/
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
//保證promise2的onFulfilled或者onRejected只被呼叫一次 防止多次呼叫
//比如:
/**
* new Promise((resolve,reject)=>{
* resolve(xxx);
* reject(xxx);
* resolve(xxx);
* });
* 這樣就會導致promise2的onFulfilled或者onRejected被多次呼叫
*/
let called = false;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
//then be x.then=>取出then
const then = x.then;
// 如果then是函式,就默認是promise了
if (typeof then === 'function') {
then.call(x,
//If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).=> 如果/何時resolvePromise使用值呼叫y,請運行[[Resolve]](promise, y),
(y) => {
//只能呼叫一次
if (called) return;
called = true;
//如果y依舊是一個promise 那么就遞回決議
/**
* 例子:
* new Promose((resolve,reject)=>{
* resolve('xxx');
* }).then((v)=>{
* return new Promise((resolve,reject)=>{
* setTimeout(()=>{
* resolve(new Promise((resolve,reject)=>{
* resolve(new Promise((resolve,reject)=>{
* resolve(new Promise(...);//嵌套地獄
* }))
* }))
* }13000)
* })
* })
*/
resolvePromise(promise2, y, resolve, reject);
},
//If/when rejectPromise is called with a reason r, reject promise with r.=> 如果/當rejectPromise是帶一個理由r,拒絕promise與r,
(r) => {
//只能呼叫一次
if (called) return;
called = true;
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
//取then失敗或者流程報錯走到這里
if (called) return;
called = true;
reject(e);
}
} else {
//If x is not an object or function, fulfill promise with x.=>如果x不是一個物件或者函式
resolve(x);
}
}
class Promise {
/**
* @description Promise 構造器主要用于包裝不支持promise(回傳值不是Promise)的函式,
* @param {*} executor
*/
constructor(executor) {
if (isPromise(executor)) {
// Promise 構造器主要用于包裝不支持promise(回傳值不是Promise)的函式
throw new TypeError("Promise resolver #<Promise> is not a function");
}
//私有屬性 這里為什么是callbacks(一個事件佇列)?請看下面的例子:
/**
* const promise=new Promise((resolve,reject)=>{...});
* promise.then(...);
* promise.then(...);
* promise.then(...);
* promise.then(...);
* ...可以無窮盡也
* 根據promise/A+規范 所有的onFulfilled或者onRejected必須按照原呼叫順序執行 所以這里才是一個佇列
*/
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
this.onFinallyCallbacks = [];
this.reason = undefined;
this.value = undefined;
this.state = PEDDING;
const reject = (reason) => {
if (this.state === PEDDING) {
this.state = REJECTED;
//reason=reject(xxx)中傳遞的xxx
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback());
this.onFinallyCallbacks.forEach(callback => callback());
}
}
const resolve = (value) => {
if (this.state === PEDDING) {
this.state = FULFILLED;
//value=resolve(xxx)中傳遞的xxx
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback());
this.onFinallyCallbacks.forEach(callback => callback());
}
}
try {
executor && typeof executor === 'function' && executor(resolve, reject);
} catch (err) {
reject(err);
}
}
/**
* @todo //規范:
// 當一個 Promise 完成(fulfilled)或者失敗(rejected)時,回傳函式將被異步呼叫(由當前的執行緒回圈來調度完成).
具體的回傳值依據以下規則回傳,如果 then 中的回呼函式:
// 回傳了一個值,那么 then 回傳的 Promise 將會成為接受狀態,并且將回傳的值作為接受狀態的回呼函式的引數值,
// 沒有回傳任何值,那么 then 回傳的 Promise 將會成為接受狀態,并且該接受狀態的回呼函式的引數值為 undefined,
// 拋出一個錯誤,那么 then 回傳的 Promise 將會成為拒絕狀態,并且將拋出的錯誤作為拒絕狀態的回呼函式的引數值,
// 回傳一個已經是接受狀態的 Promise,那么 then 回傳的 Promise 也會成為接受狀態,
并且將那個 Promise 的接受狀態的回呼函式的引數值作為該被回傳的Promise的接受狀態回呼函式的引數值,
// 回傳一個已經是拒絕狀態的 Promise,那么 then 回傳的 Promise 也會成為拒絕狀態,
并且將那個 Promise 的拒絕狀態的回呼函式的引數值作為該被回傳的Promise的拒絕狀態回呼函式的引數值,
// 回傳一個未定狀態(pending)的 Promise,那么 then 回傳 Promise 的狀態也是未定的,并且它的終態與那個 Promise 的終態相同;
同時,它變為終態時呼叫的回呼函式引數與那個 Promise 變為終態時的回呼函式的引數是相同的,
* @param {*} onFulfilled 當 Promise 變成接受狀態(fulfilled)時呼叫的函式,該函式有一個引數,即接受的最終結果(the fulfillment value),
* 如果該引數不是函式,則會在內部被替換為 (x) => x,即原樣回傳 promise 最終結果的函式
* @param {*} onRejected 當 Promise 變成拒絕狀態(rejected)時呼叫的函式,該函式有一個引數,即拒絕的原因(rejection reason),
* 如果該引數不是函式,則會在內部被替換為一個 "Thrower" 函式 (it throws an error it received as argument),
* @returns {Promise}
*/
then(onFulfilled, onRejected) {
if (typeof onFulfilled != 'function') {
//如果該引數不是函式,則會在內部被替換為 (x) => x,即原樣回傳 promise 最終結果的函式
onFulfilled = (x) => x;
}
if (typeof onRejected != 'function') {
// 如果該引數不是函式,則會在內部被替換為一個 "Thrower" 函式 (it throws an error it received as argument)
onRejected = (reason) => { throw reason };
}
//偷懶函式 少寫重復代碼
const handler = (promise2, valueOrReason, onFOrR, resolve, reject) => {
try {
const result = onFOrR(valueOrReason);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
}
const promise2 = new Promise((resolve, reject) => {
try {
if (this.state === PEDDING) {
//當前Promise處于pedding狀態下 則將onFulfilled和onRejected加入回呼佇列中 等待Promise的狀態被改變時呼叫
this.onFulfilledCallbacks.push(
() => {
//這里為什么用setTimeout? =>2.2.4: `onFulfilled` or `onRejected` must not be called until the execution context stack contains
//only platform code. Clean-stack execution ordering tests (fulfillment case) when the promise is fulfilled asynchronously
//timeout of 200ms exceeded. Ensure the done() callback is being called in this test
setTimeout(() => {
/**
* resolvePromise這個是對 最頂層的Promise嵌套問題
* 這里的處理promise/A+并沒有規范,但是ESCMSCript6的Promise擴展了這個功能,所以把es6的擴展也實作一下
* 例子:
* const new Promose((resolve,reject)=>{
* resolve(new Promise((resolve,reject)=>{
* new Promise(...)
* }))
* })
*/
resolvePromise(
promise2,
this.value,
(v) => { handler(promise2, v, onFulfilled, resolve, reject); },
(r) => { handler(promise2, r, onRejected, resolve, reject); }
);
}, 0);
// setTimeout(() => handler(promise2, this.value, onFulfilled, resolve, reject), 0);
}
);
this.onRejectedCallbacks.push(
() => {
setTimeout(() => handler(promise2, this.reason, onRejected, resolve, reject), 0);
}
);
} else if (this.state === FULFILLED) {
//當前Promise處于fulfilled狀態下 則“直接呼叫” 這里通過setTimeout來執行異步任務
setTimeout(() => {
resolvePromise(
promise2,
this.value,
(v) => { handler(promise2, v, onFulfilled, resolve, reject); },
(r) => { handler(promise2, r, onRejected, resolve, reject); }
);
}, 0);
} else if (this.state === REJECTED) {
//當前Promise處于rejected狀態下 則“直接呼叫” 這里通過setTimeout來執行異步任務 模擬微任務
setTimeout(() => handler(promise2, this.reason, onRejected, resolve, reject), 0);
}
} catch (err) {
//整個exctutor運行發生例外 則直接reject
reject(err);
}
});
return promise2;
}
/**
* @todo 規范: catch() 方法回傳一個Promise (en-US),并且處理拒絕的情況,它的行為與呼叫Promise.prototype.then(undefined, onRejected) 相同,
* (事實上, calling obj.catch(onRejected) 內部calls obj.then(undefined, onRejected)).
*
* @description catch 方法可以用于您的promise組合中的錯誤處理,
* @param {*} onRejected 當Promise 被rejected時,被呼叫的一個Function, 該函式擁有一個引數:reason rejection 的原因,
* 如果 onRejected 拋出一個錯誤或回傳一個本身失敗的 Promise , 通過 catch() 回傳的Promise 被rejected;否則,它將顯示為成功(resolved),
* @returns {Promise}
*/
catch (onRejected) {
//事實上, calling obj.catch(onRejected) 內部calls obj.then(undefined, onRejected)
return this.then(undefined, onRejected);
}
/**
* @todo 規范: finally() 方法回傳一個Promise,在promise結束時,無論結果是fulfilled或者是rejected,都會執行指定的回呼函式,
* 這為在Promise是否成功完成后都需要執行的代碼提供了一種方式,這避免了同樣的陳述句需要在then()和catch()中各寫一次的情況,
* @description 如果你想在 promise 執行完畢后無論其結果怎樣都做一些處理或清理時,finally() 方法可能是有用的,
finally() 雖然與 .then(onFinally, onFinally) 類似,它們不同的是:
呼叫行內函式時,不需要多次宣告該函式或為該函式創建一個變數保存它,
由于無法知道promise的最終狀態,所以finally的回呼函式中不接收任何引數,它僅用于無論最終結果如何都要執行的情況,
與Promise.resolve(2).then(() => {}, () => {}) (resolved的結果為undefined)不同,Promise.resolve(2).finally(() => {}) resolved的結果為 2,
同樣,Promise.reject(3).then(() => {}, () => {}) (resolved 的結果為undefined), Promise.reject(3).finally(() => {}) rejected 的結果為 3,
注意: 在finally回呼中 throw(或回傳被拒絕的promise)將以 throw() 指定的原因拒絕新的promise.
* @param {*} onFinally
* @returns {Promise} 回傳一個設定了 finally 回呼函式的Promise物件,
*/
finally(onFinally) {
return new Promise((resolve, reject) => {
if (this.state == FULFILLED) {
setTimeout(() => {
try {
onFinally();
resolve(this.value);
} catch (err) {
reject(err);
}
}, 0);
} else if (this.state === REJECTED) {
setTimeout(() => {
try {
onFinally();
resolve(this.reason);
} catch (err) {
reject(err);
}
}, 0);
} else if (this.state === PEDDING) {
this.onFinallyCallbacks.push(() => {
try {
onFinally();
resolve(this.state === FULFILLED ? this.value : this.reason);
} catch (err) {
reject(err);
}
});
}
});
}
/**
* @static 靜態方法
* @description 規范: Promise.resolve(value)方法回傳一個以給定值決議后的Promise 物件,如果這個值是一個 promise,那么將回傳這個 promise;
* 如果這個值是thenable(即帶有"then" 方法),回傳的promise會“跟隨”這個thenable的物件,采用它的最終狀態;
* 否則回傳的promise將以此值完成,此函式將類promise物件的多層嵌套展平,
* @warning 不要在決議為自身的thenable 上呼叫Promise.resolve,這將導致無限遞回,因為它試圖展平無限嵌套的promise,
* @param {*} value
* @returns {Promise}
*/
static resolve(value) {
return new Promise((resolve, reject) => {
if (isPromise(value)) {
value.then(resolve, reject);
} else {
resolve(value)
}
});
}
/**
* @todo Promise.reject()方法回傳一個帶有拒絕原因的Promise物件,
* @static
* @description 靜態函式Promise.reject回傳一個被拒絕的Promise物件,通過使用Error的實體獲取錯誤原因reason對除錯和選擇性錯誤捕捉很有幫助,
* @param {*} reason
* @returns {Promise}
*/
static reject(reason) {
return new Promise((_, reject) => {
reject(reason);
});
}
/**
* @todo 規范: Promise.all() 方法接收一個promise的iterable型別(注:Array,Map,Set都屬于ES6的iterable型別)的輸入,
* 并且只回傳一個Promise實體, 那個輸入的所有promise的resolve回呼的結果是一個陣列,這個Promise的resolve回呼執行是在
* 所有輸入的promise的resolve回呼都結束,或者輸入的iterable里沒有promise了的時候,它的reject回呼執行是,只要任何一個輸入的
* promise的reject回呼執行或者輸入不合法的promise就會立即拋出錯誤,并且reject的是第一個拋出的錯誤資訊,
* @description Promise.allSettled()不管引數中的promise是fulfilled還是rejected,都會等引數中的實體都回傳結果,包裝實體才會結束,
* Promise.all()只有在接受的所有promise實體全部是fulfilled才會走Promise.all([p1,p2,p3]).then()方法,
* 只要有其中一個promise實體是rejected,就會直接走catch方法,并且catch中只會回傳第一個變成rejected的promise的錯誤
* @param {*} iterable
* @returns {Promise} 規范: 如果傳入的引數是一個空的可迭代物件,則回傳一個已完成(already resolved)狀態的 Promise,
如果傳入的引數不包含任何 promise,則回傳一個異步完成(asynchronously resolved) Promise,
注意:Google Chrome 58 在這種情況下回傳一個已完成(already resolved)狀態的 Promise,
其它情況下回傳一個處理中(pending)的Promise,這個回傳的 promise 之后會在所有的 promise
都完成或有一個 promise 失敗時異步地變為完成或失敗,
回傳值將會按照引數內的 promise 順序排列,而不是由呼叫 promise 的完成順序決定,
*/
static all(iterable) {
return new Promise((resolve, reject) => {
try {
let values = [],
len = 0, //用來標記已迭代元素的數量 因為iterable可能是用戶自定義迭代器物件(沒有length或者size屬性),
isWalkComplete = false,
promiseList = [], //用一個陣列保存住按照iterable中的排序的所有promise物件
promise;
const getSortPromiseValue = () => promiseList.map(p => p.value);
for (const iter of iterable) {
promise = !isPromise(iter) ? /***傳入的引數里面不是promise,將它轉變成promise***/ Promise.resolve(iter) : iter;
promiseList.push(promise); //復制或者說保存當前順序的promise的參考
//執行then方法
promise.then(
(v) => {
values.push(v);
if (
typeof iterable === 'string' ||
Array.isArray(iterable) ||
iterable instanceof Map ||
iterable instanceof Set
) {
if (values.length === (iterable.length || iterable.size)) {
//處理回傳值的順序
values = getSortPromiseValue();
resolve(values);
}
} else if (isWalkComplete && values.length === len) {
//處理回傳值的順序
values = getSortPromiseValue();
resolve(values)
}
},
reason => reject(reason) //傳入第一個發生reject的reason
); //then end
len++;
} //end for
isWalkComplete = true;
} catch (err) {
reject(err);
}
});
}
/**
* @todo 該Promise.allSettled()方法回傳一個在所有給定的promise都已經fulfilled或rejected后的promise,
* 并帶有一個物件陣列,每個物件表示對應的promise結果,
當您有多個彼此不依賴的異步任務成功完成時,或者您總是想知道每個promise的結果時,通常使用它,
相比之下,Promise.all() 更適合彼此相互依賴或者在其中任何一個reject時立即結束
* @param {*} iterable 一個可迭代的物件,例如Array,其中每個成員都是Promise,
* @returns {Promise} 一旦所指定的 promises 集合中每一個 promise 已經完成,無論是成功的達成或被拒絕,未決議的 Promise將被異步完成,
* 那時,所回傳的 promise 的處理器將傳入一個陣列作為輸入,該陣列包含原始 promises 集中每個 promise 的結果,
對于每個結果物件,都有一個 status 字串,如果它的值為 fulfilled,則結果物件上存在一個 value ,如果值為 rejected,
則存在一個 reason ,value(或 reason )反映了每個 promise 決議(或拒絕)的值,
*/
static allSettled(iterable) {
return new Promise((resolve, reject) => {
//已經完成了的Promose 不管是狀態是fulfilled還是rejected
let completePromiseList = [],
promiseList = [],
len = 0,
completePromiseCount = 0,
isWalkComplete = false;
const getSortPromiseStatus = () => {
return promiseList.map(p => {
return {
status: p.state,
[p.state === FULFILLED ? 'value' : 'reason']: p.state === FULFILLED ? p.value : p.reason
}
});
};
for (const x of iterable) {
let promise = !isPromise(x) ? Promise.resolve(x) : x;
promiseList.push(promise);
promise.finally(() => {
completePromiseCount++;
if (isWalkComplete && completePromiseCount === len) {
completePromiseList = getSortPromiseStatus();
resolve(completePromiseList);
}
});
len++;
}
isWalkComplete = true;
});
}
/**
* @todo Promise.race(iterable) 方法回傳一個 promise,一旦迭代器中的某個promise解決或拒絕,回傳的 promise就會解決或拒絕,
* @description race 函式回傳一個 Promise,它將與第一個傳遞的 promise 相同的完成方式被完成,
* 它可以是完成( resolves),也可以是失敗(rejects),這要取決于第一個完成的方式是兩個中的哪個,
如果傳的迭代是空的,則回傳的 promise 將永遠等待,
如果迭代包含一個或多個非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將決議為迭代中找到的第一個值,
* @param {*} iterable 可迭代物件,類似Array,詳見 iterable,
* @returns {Promise} 一個待定的 Promise 只要給定的迭代中的一個promise解決或拒絕,就采用第一個promise的值作為它的值,
* 從而異步地決議或拒絕(一旦堆疊為空),
*/
static race(iterable) {
return new Promise((resolve, reject) => {
for (const iter of iterable) {
//如果迭代包含一個或多個非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將決議為迭代中找到的第一個值,
if (isPromise(iter)) {
//如果iter是個promise
const promise = iter;
//判斷promise的狀態來動態選擇接受或者拒絕
if (promise.state === FULFILLED) {
promise.then(resolve);
} else if (promise.state === REJECTED) {
promise.then(undefined, reject);
} else if (promise.state === PEDDING) {
promise.then(resolve, reject);
}
} else {
//非promise型別直接resolve
resolve(iter)
}
}
});
}
/**
* @todo ECMAScript6的檔案規范: Promise.any() 接收一個Promise可迭代物件,只要其中的一個 promise 成功,就回傳那個已經成功的 promise ,
* 如果可迭代物件中沒有一個 promise 成功(即所有的 promises 都失敗/拒絕),就回傳一個失敗的 promise 和AggregateError型別的實體,
* 它是 Error 的一個子類,用于把單一的錯誤集合在一起,本質上,這個方法和Promise.all()是相反的,
* @description 這個方法用于回傳第一個成功的 promise ,只要有一個 promise 成功此方法就會終止,它不會等待其他的 promise 全部完成,
不像 Promise.all() 會回傳一組完成值那樣(resolved values),我們只能得到一個成功值(假設至少有一個 promise 完成),
當我們只需要一個 promise 成功,而不關心是哪一個成功時此方法很有用的,
同時, 也不像 Promise.race() 總是回傳第一個結果值(resolved/reject)那樣,這個方法回傳的是第一個 成功的 值,
這個方法將會忽略掉所有被拒絕的 promise,直到第一個 promise 成功,
* @warning Promise.any() 方法依然是實驗性的,尚未被所有的瀏覽器完全支持,它當前處于 TC39 第四階段草案(Stage 4)
* @param {*} iterable 一個可迭代的物件, 例如 Array、Set、Map、String
* @returns {Promise} 如果傳入的引數是一個空的可迭代物件,則回傳一個 已失敗(already rejected) 狀態的 Promise,
如果傳入的引數不包含任何 promise,則回傳一個 異步完成 (asynchronously resolved)的 Promise,
其他情況下都會回傳一個處理中(pending) 的 Promise, 只要傳入的迭代物件中的任何一個 promise 變成成功(resolve)
狀態,或者其中的所有的 promises 都失敗,那么回傳的 promise 就會 異步地(當呼叫堆疊為空時)
變成成功/失敗(resolved/reject)狀態,
*/
static any(iterable) {
return new Promise((resolve, reject) => {
let len = 0, //記錄迭代器中元素的數量
isWalkComplete = false, //標識迭代器遍歷完成
promiseList = [], //用一個陣列保存住按照iterable中的排序的所有promise物件
errors = []; //記錄所有的錯誤
const getSortPromiseReason = () => promiseList.map(p => p.reason);
for (const iter of iterable) {
if (isPromise(iter)) {
const promise = iter;
promiseList.push(promise);
promise.then(
v => {
resolve(v);
return;
},
reason => {
errors.push(reason);
//迭代器遍歷完成 但是所有的promise值都失敗了
if (isWalkComplete && errors.length === len) {
//獲取排序后的promise的reason
errors = getSortPromiseReason();
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
} else {
resolve(iter);
}
len++;
}
isWalkComplete = true;
//判斷迭代器是否為空
if (len === 0) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/277690.html
標籤:其他
上一篇:JavaWeb學習記錄之JSP(隨時更新,菜鳥一只,歡迎各位大佬斧正)
下一篇:js動態添加,jq,ajax

