如何用Promise.all模拟allSettled

1 篇文章 0 订阅

用过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都等到了最后。唯一需要注意的是这里即使有子任务失败,最终总的结果也是成功的。需要的话,你可能需要另外的变量存储子任务的结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值