4. Promise中的all和race

在做下面👇的题目之前,让我们先来了解一下Promise.all()Promise.race()的用法。

通俗来说,.all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。

.race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。

来看看题目一。

4.1 题目一

我们知道如果直接在脚本文件中定义一个Promise,它构造函数的第一个参数是会立即执行的,就像这样:

const p1 = newPromise(r =>console.log('立即打印'))

控制台中会立即打印出 “立即打印”。

因此为了控制它什么时候执行,我们可以用一个函数包裹着它,在需要它执行的时候,调用这个函数就可以了:

function runP1 () {
    const p1 = newPromise(r =>console.log('立即打印'))
    return p1
}

runP1() // 调用此函数时才执行

OK 👌, 让我们回归正题。

现在来构建这么一个函数:

function runAsync (x) {
    const p = newPromise(r => setTimeout(() => r(x, console.log(x)), 1000))
    return p
}

 

该函数传入一个值x,然后间隔一秒后打印出这个x

如果我用.all()来执行它会怎样呢?

function runAsync (x) {
    const p = newPromise(r => setTimeout(() => r(x, console.log(x)), 1000))
    return p
}
Promise.all([runAsync(1), runAsync(2), runAsync(3)])
  .then(res =>console.log(res))

先来想想此段代码在浏览器中会如何执行?

没错,当你打开页面的时候,在间隔一秒后,控制台会同时打印出1, 2, 3,还有一个数组[1, 2, 3]

1
2
3
[1, 2, 3]

所以你现在能理解这句话的意思了吗:有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。

.all()后面的.then()里的回调函数接收的就是所有异步操作的结果。

而且这个结果中数组的顺序和Promise.all()接收到的数组顺序一致!!!

4.2 题目二

我新增了一个runReject函数,它用来在1000 * x秒后reject一个错误。

同时.catch()函数能够捕获到.all()里最先的那个异常,并且只执行一次。

想想这道题会怎样执行呢 🤔️?

function runAsync (x) {
  const p = newPromise(r => setTimeout(() => r(x, console.log(x)), 1000))
  return p
}
function runReject (x) {
  const p = newPromise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
  return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
  .then(res =>console.log(res))
  .catch(err =>console.log(err))
1
3
// 2s后输出
2
Error: 2
// 4s后输出
4
没错,就像我之前说的,.catch是会捕获最先的那个异常,在这道题目中最先的异常就是runReject(2)的结果。

另外,如果一组异步操作中有一个异常都不会进入.then()的第一个回调函数参数中。

注意,为什么不说是不进入.then()中呢 🤔️?

哈哈,大家别忘了.then()方法的第二个参数也是可以捕获错误的:
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
  .then(res =>console.log(res),
  err => console.log(err))

4.3 题目三

接下来让我们看看另一个有趣的方法.race

让我看看你们的英语水平如何?

快!一秒钟告诉我race是什么意思?

race,比赛,赛跑的意思。

所以使用.race()方法,它只会获取最先执行完成的那个结果,其它的异步任务虽然也会继续进行下去,不过race已经不管那些任务的结果了。

来,改造一下4.1这道题:

function runAsync (x) {
  const p = newPromise(r => setTimeout(() => r(x, console.log(x)), 1000))
  return p
}
Promise.race([runAsync(1), runAsync(2), runAsync(3)])
  .then(res =>console.log('result: ', res))
  .catch(err =>console.log(err))

执行结果为

1
'result: ' 1
2
3

4.4 题目四

改造一下题目4.2

function runAsync(x) {
  const p = newPromise(r =>
    setTimeout(() => r(x, console.log(x)), 1000)
  );
  return p;
}
function runReject(x) {
  const p = newPromise((res, rej) =>
    setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x)
  );
  return p;
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)])
  .then(res =>console.log("result: ", res))
  .catch(err =>console.log(err));

遇到错误的话,也是一样的,在这道题中,runReject(0)最先执行完,所以进入了catch()中:

0
'Error: 0'
1
2
3

总结

好的,让我们来总结一下.then().race()吧,😄

  • Promise.all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
  • .race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
  • Promise.all().then()结果中数组的顺序和Promise.all()接收到的数组顺序一致。
posted on 2021-01-20 17:30  京鸿一瞥  阅读(239)  评论(0)    收藏  举报