Promise.allSettled 的作用,如何自己实现一个 Promise.allSettled

开发 前端
只要其中任何一个promise 失败都会执行 reject ,并且 reject 的是第一个抛出的错误信息,只有所有的 promise 都 resolve 时才会调用 .then 中的成功回调。

[[396102]]

本文转载自微信公众号「三分钟学前端」,作者sisterAn。转载本文请联系三分钟学前端公众号。

引言

本文从四个方面循序渐进介绍 Promise.allSettled :

  • Promise.all() 的缺陷
  • 引入 Promise.allSettled()
  • Promise.allSettled() 与 Promise.all() 各自的适用场景
  • 手写 Promise.allSettled() 实现

下面正文开始??

Promise.all() 的缺陷

我们在之前的一篇文章中 面试官问:Promise.all 使用、原理实现及错误处理 已经介绍过,当我们使用 Promise.all() 执行过个 promise 时,只要其中任何一个promise 失败都会执行 reject ,并且 reject 的是第一个抛出的错误信息,只有所有的 promise 都 resolve 时才会调用 .then 中的成功回调

  1. const p1 = Promise.resolve(1) 
  2. const p2 = Promise.resolve(2) 
  3. const p3 = new Promise((resolve, reject) => { 
  4.   setTimeout(reject, 1000, 'three'); 
  5. }); 
  6.  
  7. Promise.all([p1, p2, p3]) 
  8. .then(values => { 
  9.     console.log('resolve: 'values
  10. }).catch(err => { 
  11.     console.log('reject: ', err) 
  12. })  
  13.  
  14. // reject:  three 

注意:其中任意一个 promise 被 reject ,Promise.all 就会立即被 reject ,数组中其它未执行完的 promise 依然是在执行的, Promise.all 没有采取任何措施来取消它们的执行

但大多数场景中,我们期望传入的这组 promise 无论执行失败或成功,都能获取每个 promise 的执行结果,为此,ES2020 引入了 Promise.allSettled()

Promise.allSettled()

Promise.allSettled() 可以获取数组中每个 promise 的结果,无论成功或失败

  1. const p1 = Promise.resolve(1) 
  2. const p2 = Promise.resolve(2) 
  3. const p3 = new Promise((resolve, reject) => { 
  4.   setTimeout(reject, 1000, 'three'); 
  5. }); 
  6.  
  7. Promise.allSettled([p1, p2, p3]) 
  8. .then(values => { 
  9.     console.log(values
  10. })  
  11.  
  12. /* 
  13.   {status: "fulfilled", value: 1},  
  14.   {status: "fulfilled", value: 2},  
  15.   {status: "rejected", reason: "three"
  16. */ 

当浏览器不支持 Promise.allSettled ,可以如此 polyfill:

  1. if (!Promise.allSettled) { 
  2.   const rejectHandler = reason => ({status: "rejected", reason}) 
  3.   const resolveHandler = value => ({status: "fulfilled", value}) 
  4.   Promise.allSettled = promises => 
  5.     Promise.all
  6.       promises.map((promise) => 
  7.         Promise.resolve(promise)  
  8.           .then(resolveHandler, rejectHandler) 
  9.       ) 
  10.       // 每个 promise 需要用 Promise.resolve 包裹下 
  11.       // 以防传递非 promise 
  12.     ); 
  13.  
  14. // 使用 
  15. const p1 = Promise.resolve(1) 
  16. const p2 = Promise.resolve(2) 
  17. const p3 = new Promise((resolve, reject) => { 
  18.   setTimeout(reject, 1000, 'three'); 
  19. }) 
  20. const promises = [p1, p2, p3] 
  21. Promise.allSettled(promises).then(console.log) 

Promise.allSettled() 与 Promise.all() 各自的适用场景

Promise.allSettled() 更适合:

  • 彼此不依赖,其中任何一个被 reject ,对其它都没有影响
  • 期望知道每个 promise 的执行结果

Promise.all() 更适合:

  • 彼此相互依赖,其中任何一个被 reject ,其它都失去了实际价值

手写 Promise.allSettled 源码

与 Promise.all 不同的是,当 promise 被 reject 之后,我们不会直接 reject ,而是记录下该 reject 的值和对应的状态 'rejected' ;

同样地,当 promise 对象被 resolve 时我们也不仅仅局限于记录值,同时也会记录状态 'fulfilled' 。

当所有的 promise 对象都已执行(解决或拒绝),我们统一 resolve 所有的 promise 执行结果数组

  1. MyPromise.allSettled = function (promises) { 
  2.     return new MyPromise((resolve, reject) => { 
  3.       promises = Array.isArray(promises) ? promises : [] 
  4.       let len = promises.length 
  5.       const argslen = len 
  6.       // 如果传入的是一个空数组,那么就直接返回一个resolved的空数组promise对象 
  7.       if (len === 0) return resolve([]) 
  8.       // 将传入的参数转化为数组,赋给args变量 
  9.       let args = Array.prototype.slice.call(promises) 
  10.       // 计算当前是否所有的 promise 执行完成,执行完毕则resolve 
  11.       const compute = () => { 
  12.         if(--len === 0) {  
  13.           resolve(args) 
  14.         } 
  15.       } 
  16.       function resolvePromise(index, value) { 
  17.         // 判断传入的是否是 promise 类型 
  18.         if(value instanceof MyPromise) {  
  19.           const then = value.then 
  20.           then.call(value, function(val) { 
  21.             args[index] = { status: 'fulfilled', value: val} 
  22.             compute() 
  23.           }, function(e) { 
  24.             args[index] = { status: 'rejected', reason: e } 
  25.             compute() 
  26.           }) 
  27.         } else { 
  28.           args[index] = { status: 'fulfilled', value: value} 
  29.           compute() 
  30.         } 
  31.       } 
  32.     
  33.       for(let i = 0; i < argslen; i++){ 
  34.         resolvePromise(i, args[i]) 
  35.       } 
  36.     }) 
  37.   } 

总结

彼此相互依赖,一个失败全部失效(全无或全有)用 Promise.all ;相互独立,获取每个结果用 Promise.allSettled

来自:https://github.com/sisterAn/blog

 

责任编辑:武晓燕 来源: 三分钟学前端
相关推荐

2023-10-04 07:25:59

JavaScriptpromises

2021-04-28 08:21:21

Promise.any服务器场景

2023-07-11 09:07:49

数组Promise方法

2021-04-29 08:28:24

架构参数传递

2020-09-24 11:46:03

Promise

2018-03-13 16:04:45

Promise执行顺序

2018-07-03 15:20:36

Promise函数借钱

2020-12-15 08:01:24

Promise参数ES6

2023-09-15 15:31:23

异步编程Promise

2017-05-11 20:20:59

JavascriptPromiseWeb

2020-07-29 17:35:08

Promise源码前端

2021-09-02 12:07:48

Swift 监听系统Promise

2021-03-09 07:37:42

技术Promise测试

2022-09-28 12:23:36

Promise代码

2022-09-15 07:54:59

awaitPromise

2017-04-10 15:57:10

AsyncAwaitPromise

2024-01-08 13:47:00

代码分析工具

2015-07-23 11:59:27

JavascriptPromise

2022-01-21 08:50:15

Promise任务队列前端

2024-03-06 13:56:00

项目awaitpromise
点赞
收藏

51CTO技术栈公众号