由reduce引发的Promise决议思考

由reduce引发的Promise决议思考

十月 06, 2020

reduce有哪些奇淫巧技

  • 最基本的累加数
  • 数组转对象
  • 顺序执行异步任务

本文不再阐述一些比较官方的话语。

reduce方法的MDN传送门

最基本的累加

1
2
const arr = [1, 2, 3];
const addResult = arr.reduce((a, b) => a+b);

数组转对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 用过 loadsh 的小伙伴都应该知道,lodash 提供了_keyBy 提供了这样的功能
const data = [{
name: '张飒',
id: 1
}, {
name: '李四',
id: 2
}, {
name: '赵柳',
id: 3
}]

const targetObj = data.reduce((a, b) => { ...a, { [b.id]: b } }, {});

// console
// { 1: { name: '张飒', id: 1 }, 2: { name: '李四', id: 2 }, 3: { name: '赵柳', id: 3 }}

顺序执行异步任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const PromiseTaskA = () => new Promise((resolve) => { setTimeout(() => {
console.log('即将执行A');
resolve('PromiseTaskA');
}, 2000) })
const PromiseTaskB = () => new Promise((resolve) => { setTimeout(() => {
console.log('即将执行B');
resolve('PromiseTaskB');
}, 2000) })
const PromiseTaskC = () => new Promise((resolve) => { setTimeout(() => {
console.log('即将执行C');
resolve('PromiseTaskC');
}, 1000) })

const tasks = [PromiseTaskA, PromiseTaskC, PromiseTaskB];
tasks.reduce((a, b) => {
console.log(a, '00')
return a.then(() => b())
}, Promise.resolve({}) )
.then(() => {
console.log('all done')
});

// console.log
// Promise { {} } 00
// Promise { <pending> } 00
// Promise { <pending> } 00
// 即将执行A
// 即将执行C
// 即将执行B
// all done

当到这里的时候,我突然联想到一个问题,Promise.all是顺序执行的吗?为什么他可以在then里对应传入异步任务数组返回相应的结果?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const PromiseTaskA = () => new Promise((resolve) => { setTimeout(() => {
console.log('即将执行A');
resolve('PromiseTaskA');
}, 2000) })
const PromiseTaskB = () => new Promise((resolve) => { setTimeout(() => {
console.log('即将执行B');
resolve('PromiseTaskB');
}, 2000) })
const PromiseTaskC = () => new Promise((resolve) => { setTimeout(() => {
console.log('即将执行C');
resolve('PromiseTaskC');
}, 1000) })

Promise.all([PromiseTaskA(), PromiseTaskB(), PromiseTaskC()])
.then(res => {
console.log(res)
});

// console
// 即将执行C
// 即将执行A
// 即将执行B
// [ 'PromiseTaskA', 'PromiseTaskB', 'PromiseTaskC' ]

原因很简单,Promise.all是并行的,也就是宏观意义上的并行,也可以说是同时执行,当哪个异步任务执行结束,就把对应的执行结果塞进数组内部,所以就可以实现结果对应。

Promise.all并不会顺序执行,请不要依赖Promise.all去做顺序执行流程任务。

问题又来了?怎么保证Promise的执行尽管失败了,但是Promise.all并不会中断?

其实也很好解决,把异步任务的catchresolve出来,保证整个并行任务流的正常运行。

扩展一个知识点,Promise为什么会发生值透传?

1
2
3
4
5
6
7
8
Promise.resolve(1)
.then(3)
.then(data => {
console.log(data)
})

// console?
// 1

原因也很简单,因为Promisethencatch期望的是一个函数,如果出现!Function就会发生透传。

继续扩展一个知识点,Promise是微任务吗?then是同步还是异步的。

Promise构造函数是同步的,thencatch也是同步的,但是内部的callback被扔进了异步队列里。