Javascript异步转同步篇二——Promise.all/allSettled

974 阅读2分钟

这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

哎呀~开心,终于日更要收工了!

今天接着昨天讲Javascript的Promise同步。

多个Promise同步执行问题

昨天我们阐述了一个Promise与其他代码的同步问题,可以通过以下代码的方式来执行:

new Promise(resolve => {
    resolve()
}).then(() => {
    // 同步代码
})

那么多个Promise如何保持同步呢,即假如同步代码也是多个Promise呢?

链式结构

首先,我们知道可以按照这样的层次来组织,如下:

promiseA().then(() => {
    promiseB.then(() => {
        promiseC.then(()=> {
            ....
        })
    })
})

这样是符合Promise规则的,但是这样的编码会导致代码的嵌套层次越来越高。

由此便引入了Promise的链式结构,如下:

promiseA().then((xxx) => {xxx})
          .then(XXX => {XXX})
          .then(xxxx => {
              xxxx
          })
})

Promise.all

生产环境中有一种场景是: 任务C在任务A,任务B执行完毕后再开始执行。如果我们有Java后台并发编程的经验,应该知道Java有个并发工具类叫:CountDownLatch,通过countDownLatch.await()阻塞线程直到其他所有的前置任务完成后再执行后续任务。

那么Promise这么强大,是否也有同样的类似机制呢?

这便是Promise.all,基础用法:

Promise.all([promiseA, promiseB]).then((values) => {
  // 省略的其他任务代码
});

完整的示例大家可以在官方文档中查看。

Promise.all(xx)方法相似的还有一个Promise.allSettled(),name两者有什么区别呢?

我们来看下面的两端代码:

const promise1 = Promise.resolve(3);
const promise2 = 43;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

Promise.allSettled([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

执行后,结果为:

> Array [3, 43, "foo"]
> Array [3, 43, "foo"] > Array [Object { status: "fulfilled", value: 3 }, Object { status: "fulfilled", value: 43 }, Object { status: "fulfilled", value: "foo" }]

另外,我们修改上述代码中的promise2为:

const promise2 = Promise.reject(43);

即将其中的一个promise修改为失败的状态,会发现输出结果中all不再执行,而allSettled执行结果为:

> Array [Object { status: "fulfilled", value: 3 }, Object { status: "rejected", reason: 43 }, Object { status: "fulfilled", value: "foo" }]

由此可见,all并不能处理拒绝的情况,而且allSettled方法的参数与all也不相同。

Promise的创建方式

之前我一直使用的是new Promise((resolve, reject) => {...})来创建,代码繁琐复杂,这次写文章通过阅读Promise的官方文档,发现其还可以这样用:Promise.resolve(value),例如:

Promise.resolve(43) Promise.resolve(value)

从而简化了Promise需要重叠以及多个Promise的代码复杂度问题。尤其是当我们需要将现有的Promise层级做出更改时尤为方便。