本文主要是介绍如何用Promise.all模拟allSettled,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
用过Promise 的同学都知道Promise.all的作用是把一系列的异步(Promise)对象一起执行,等待所有都成功才成功,但如果某个失败了就会立刻失败,不会等待其他未完成的任务。
不过我们有时候会想要不同的行为,就是执行一系列的异步任务,我们希望不论里面的任务成功失败,等到所有任务都结束后再结束。于是有了新的API “allSettled”。
不过现在这个API还是draft状态,只有最新的浏览器和Node js 版本才支持。如果我们要兼容旧的浏览器和Node js版本咋办呢?
答案当然是利用现有的API自己写一个类似功能的。我看到网上有人的解决方案是不用Promise.all自己计数:记下开始启动几个异步任务,每完成(成功或者失败都算)一个就减一,直到计数为0为止。这个办法让我想起来Java 的Semaphore,感觉有点类似。
我的想法是还利用Promise.all但是需要绕过它快速失败的机制,怎么办呢?其实也挺简单:把里面的子任务的promise对象再封装一次,屏蔽掉其中的失败事件即可。
下面我们来看具体的例子,我们先看普通的Promise.all 快速失败的情况:
function getTask(n) {return new Promise((success, fail) => {setTimeout(() => {if (Math.random() > 0.5) {//随机模拟任务成功失败console.log('Task ' + n + ' success!');//子任务成功success();} else {console.log('Task ' + n + ' failed!');//子任务失败fail();}}, Math.random() * 3000);//随机模拟任务执行时间});
}var taskArray = [];
for (let i = 0; i < 10; i++) {//生成一批子任务taskArray.push(getTask(i));
}Promise.all(taskArray).then(() => console.log("===All done===")).catch(() => console.log("===Already Failed==="));
执行结果:
Task 6 failed!
VM165:20 ===Already Failed===
VM165:8 Task 2 failed!
VM165:5 Task 0 success!
VM165:8 Task 8 failed!
VM165:5 Task 3 success!
VM165:8 Task 4 failed!
VM165:5 Task 1 success!
VM165:8 Task 5 failed!
VM165:8 Task 9 failed!
VM165:8 Task 7 failed!
我们看到这里第一个结束的任务#6就失败了,Promise.all立刻触发了失败,没有等后面的任务结束。
我们照上面说的方法来修改一下程序,把子任务封装一下再试一次:
function getTask(n) {return new Promise((success, fail) => {setTimeout(() => {if (Math.random() > 0.5) {console.log('Task ' + n + ' success!');success();} else {console.log('Task ' + n + ' failed!');fail();}}, Math.random() * 3000);});
}var taskArray = [];
for (let i = 0; i < 10; i++) {taskArray.push(new Promise((success, fail) => {//嵌套一层Promise封装子任务。getTask(i).then(() => {success();}).catch(() => {success();//屏蔽掉子任务的失败事件。});}));
}Promise.all(taskArray).then(() => console.log("===All done===")).catch(() => console.log("===Already Failed==="));
运行结果:
Task 1 failed!
VM170:8 Task 9 failed!
VM170:8 Task 6 failed!
VM170:5 Task 4 success!
VM170:5 Task 0 success!
VM170:8 Task 2 failed!
VM170:8 Task 7 failed!
VM170:8 Task 5 failed!
VM170:8 Task 3 failed!
VM170:5 Task 8 success!
VM170:26 ===All done===
我们看到这次无论子任务成功还是失败,Promise.all都等到了最后。唯一需要注意的是这里即使有子任务失败,最终总的结果也是成功的。需要的话,你可能需要另外的变量存储子任务的结果。
这篇关于如何用Promise.all模拟allSettled的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!