Promise.allSettled 的作用,如何自己實(shí)現(xiàn)一個 Promise.allSettled
本文轉(zhuǎn)載自微信公眾號「三分鐘學(xué)前端」,作者sisterAn。轉(zhuǎn)載本文請聯(lián)系三分鐘學(xué)前端公眾號。
引言
本文從四個方面循序漸進(jìn)介紹 Promise.allSettled :
- Promise.all() 的缺陷
- 引入 Promise.allSettled()
- Promise.allSettled() 與 Promise.all() 各自的適用場景
- 手寫 Promise.allSettled() 實(shí)現(xiàn)
下面正文開始??
Promise.all() 的缺陷
我們在之前的一篇文章中 面試官問:Promise.all 使用、原理實(shí)現(xiàn)及錯誤處理 已經(jīng)介紹過,當(dāng)我們使用 Promise.all() 執(zhí)行過個 promise 時,只要其中任何一個promise 失敗都會執(zhí)行 reject ,并且 reject 的是第一個拋出的錯誤信息,只有所有的 promise 都 resolve 時才會調(diào)用 .then 中的成功回調(diào)
- const p1 = Promise.resolve(1)
- const p2 = Promise.resolve(2)
- const p3 = new Promise((resolve, reject) => {
- setTimeout(reject, 1000, 'three');
- });
- Promise.all([p1, p2, p3])
- .then(values => {
- console.log('resolve: ', values)
- }).catch(err => {
- console.log('reject: ', err)
- })
- // reject: three
注意:其中任意一個 promise 被 reject ,Promise.all 就會立即被 reject ,數(shù)組中其它未執(zhí)行完的 promise 依然是在執(zhí)行的, Promise.all 沒有采取任何措施來取消它們的執(zhí)行
但大多數(shù)場景中,我們期望傳入的這組 promise 無論執(zhí)行失敗或成功,都能獲取每個 promise 的執(zhí)行結(jié)果,為此,ES2020 引入了 Promise.allSettled()
Promise.allSettled()
Promise.allSettled() 可以獲取數(shù)組中每個 promise 的結(jié)果,無論成功或失敗
- const p1 = Promise.resolve(1)
- const p2 = Promise.resolve(2)
- const p3 = new Promise((resolve, reject) => {
- setTimeout(reject, 1000, 'three');
- });
- Promise.allSettled([p1, p2, p3])
- .then(values => {
- console.log(values)
- })
- /*
- [
- {status: "fulfilled", value: 1},
- {status: "fulfilled", value: 2},
- {status: "rejected", reason: "three"}
- ]
- */
當(dāng)瀏覽器不支持 Promise.allSettled ,可以如此 polyfill:
- if (!Promise.allSettled) {
- const rejectHandler = reason => ({status: "rejected", reason})
- const resolveHandler = value => ({status: "fulfilled", value})
- Promise.allSettled = promises =>
- Promise.all(
- promises.map((promise) =>
- Promise.resolve(promise)
- .then(resolveHandler, rejectHandler)
- )
- // 每個 promise 需要用 Promise.resolve 包裹下
- // 以防傳遞非 promise
- );
- }
- // 使用
- const p1 = Promise.resolve(1)
- const p2 = Promise.resolve(2)
- const p3 = new Promise((resolve, reject) => {
- setTimeout(reject, 1000, 'three');
- })
- const promises = [p1, p2, p3]
- Promise.allSettled(promises).then(console.log)
Promise.allSettled() 與 Promise.all() 各自的適用場景
Promise.allSettled() 更適合:
- 彼此不依賴,其中任何一個被 reject ,對其它都沒有影響
- 期望知道每個 promise 的執(zhí)行結(jié)果
Promise.all() 更適合:
- 彼此相互依賴,其中任何一個被 reject ,其它都失去了實(shí)際價值
手寫 Promise.allSettled 源碼
與 Promise.all 不同的是,當(dāng) promise 被 reject 之后,我們不會直接 reject ,而是記錄下該 reject 的值和對應(yīng)的狀態(tài) 'rejected' ;
同樣地,當(dāng) promise 對象被 resolve 時我們也不僅僅局限于記錄值,同時也會記錄狀態(tài) 'fulfilled' 。
當(dāng)所有的 promise 對象都已執(zhí)行(解決或拒絕),我們統(tǒng)一 resolve 所有的 promise 執(zhí)行結(jié)果數(shù)組
- MyPromise.allSettled = function (promises) {
- return new MyPromise((resolve, reject) => {
- promises = Array.isArray(promises) ? promises : []
- let len = promises.length
- const argslen = len
- // 如果傳入的是一個空數(shù)組,那么就直接返回一個resolved的空數(shù)組promise對象
- if (len === 0) return resolve([])
- // 將傳入的參數(shù)轉(zhuǎn)化為數(shù)組,賦給args變量
- let args = Array.prototype.slice.call(promises)
- // 計算當(dāng)前是否所有的 promise 執(zhí)行完成,執(zhí)行完畢則resolve
- const compute = () => {
- if(--len === 0) {
- resolve(args)
- }
- }
- function resolvePromise(index, value) {
- // 判斷傳入的是否是 promise 類型
- if(value instanceof MyPromise) {
- const then = value.then
- then.call(value, function(val) {
- args[index] = { status: 'fulfilled', value: val}
- compute()
- }, function(e) {
- args[index] = { status: 'rejected', reason: e }
- compute()
- })
- } else {
- args[index] = { status: 'fulfilled', value: value}
- compute()
- }
- }
- for(let i = 0; i < argslen; i++){
- resolvePromise(i, args[i])
- }
- })
- }
總結(jié)
彼此相互依賴,一個失敗全部失效(全無或全有)用 Promise.all ;相互獨(dú)立,獲取每個結(jié)果用 Promise.allSettled
來自:https://github.com/sisterAn/blog