手写Promise系列之(一):Promise-allSettled

手写Promise系列可以说是非常热门的面试题了,Promise系列的三兄弟,Promise.all(),Promise.race(),Promise.allSettled()就是经常会出现的手写题目。

那为什么这个系列第一期要先提Promise.allSettled()呢,我们来看一个表:




可以看到,Promise.allSettled()的兼容性只有85%左右,在一些比较老的机型上,甚至于在一台2019年的vivo手机上都不支持,所以这个函数的手写,不仅具有学习意义,甚至于在现实的开发过程中能成为解决兼容性的关键。

与Promise.all()的对比

Promise.all需要所有的Promise都成功之后才会resolve,一旦有一个失败就会reject,剩下的Promise都不会再去处理。这样的设计在一些场景下可能并不符合我们的预期。

比如现在我们有3个异步请求,我们需要在三个请求都结束后做一些事情。使用all时,一旦有一个请求出错,那么未完成的请求都不会再发送,不符合我们的预期,所有就有了allSettled,不论里面的任务成功失败,等到所有任务都结束后再结束。只不过在结束之后每个Promise的结果中会多一个字段,显示任务是成功的还是失败的。

利用现有的API

对比了Promise.all()和Promise.allSettled()之后我们看到,两者之间的区别无非就是遇到失败的任务之后的动作,前者直接返回失败并停止执行,后者则不管结果继续执行。

那么我们就可以利用Promise.all()实现一个Promise.allSettled(),思路很简单,就是把里面的子任务的promise对象再封装一次,使用resolve屏蔽掉其中的失败事件即可。

1
2
3
4
5
6
7
8
9
if (!Promise.allSettled) {
Promise.allSettled = function(promises) {
return Promise.all(promises.map(p => Promise.resolve(p).then(res => {
return { status: 'fulfilled', value: res };
}, error => {
return { status: 'rejected', reason: error };
})));
}
}

这样在现有API下我们就能很简便地实现这个函数

从原理和用法入手

前面我们了解到,allSettled就是等所有Promise任务完成之后,不管成功与否,一起返回,并给出特殊的标志字段status标志任务的完成情况,因此我们的思路也比较简单,执行每个任务之后暂存结果,等所有任务完成之后,将暂存的结果一并返回。基于此我们通过他的原理与用法,可以实现这一概念。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (!Promise.allSettled) {
Promise.allSettled = function(promises) {
return new Promise(resolve => {
const data = [], len = promises.length;
let count = len;
for(let i = 0; i < len; i++) {
const promise = promise[i];
promise.then(res => {
data[i] = { status: 'fulfilled', value: res };
}, error => {
data[i] = { status: 'rejected', value: error };
}).finally(() => {
if (i === count) {
resolve(data);
}
})
}
})
}
}
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2015-2021 AURORA_ZXH
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信