🌙 并行执行
Promise原生方法中提供了执行多个Promise的方式,如:
// 等待所有都成功 或 第一个失败
Promise.all(arr).then(res => console.log(res))
// 等待所有都成功 或 所有都失败
Promise.allSettled(arr).then(res => console.log(res))
// 等待任意一个成功 或 全部失败
Promise.any(arr).then(res => console.log(res))
// 等待任意一个成功 或 任意一个失败
Promise.race(arr).then(res => console.log(res))
2
3
4
5
6
7
8
9
10
11
Promise.all
、 Promise.allSettled
、 Promise.any
和 Promise.race
都是并行执行的,它们并不会按照顺序依次执行每个Promise
对象,而是同时执行多个Promise
对象。
在
Promise.all
中,所有的Promise
对象会同时被执行,而且只有当所有Promise
对象都resolve
时,Promise.all
返回的Promise
对象才会resolve
。如果其中任何一个Promise
被reject
了,Promise.all
返回的Promise
对象会立即reject
。在
Promise.allSettled
中,所有的Promise
对象也会同时被执行,不管Promise
对象的状态是resolve
还是reject
,Promise.allSettled
返回的Promise
对象都会resolve
,返回的是一个包含所有Promise
对象状态和结果的对象数组。在
Promise.any
中,所有的Promise
对象同样会同时被执行,但只要有任意一个Promise
对象resolve
,Promise.any
返回的Promise
对象就会resolve
,并且返回的是该Promise
对象的值。在
Promise.race
中,也是所有的Promise
对象同时被执行,但只要有一个Promise
对象先resolve
或者reject
,就会立即返回该Promise
对象的状态(resolve
或reject
)和结果。
🌙 串行执行
串行执行是指,不管Promise
对象的状态是resolve
还是reject
,都会依次执行下一个Promise
对象。比如:
Task A | ------>|
Task B | ------>|
Task C | ------>|
Task D | ------>|
2
3
4
准备测试代码:
// 测试示例
function testFunc(index) {
return function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Promise ' + index + ' completed.');
resolve(index);
}, Math.random() * 1000);
});
};
}
const arr = [testFunc(1), testFunc(2), testFunc(3)];
2
3
4
5
6
7
8
9
10
11
12
🌙 简单版本
Promise.resolve()
.then(() => {
return testFunc(1)();
})
.then(() => {
return testFunc(2)();
})
.then(() => {
return testFunc(3)();
})
2
3
4
5
6
7
8
9
10
🌙 使用for循环
function serialPromise(arr) {
let result = Promise.resolve();
for (let i = 0; i < arr.length; i++) {
result = result.then(() => {
return arr[i]();
});
}
return result;
}
serialPromise(arr).then(() => {
console.log('All promises completed.');
});
2
3
4
5
6
7
8
9
10
11
12
🌙 使用Array.reduce
function serialPromise(arr) {
return arr.reduce((acc, cur) => {
return acc.then(() => {
return cur();
});
}, Promise.resolve());
}
serialPromise(arr).then(() => {
console.log('All promises completed.');
});
2
3
4
5
6
7
8
9
10
11
reduce可以实现多个promise串行执行,那么map、forEach、filter等方法可以实现吗?
map 、 forEach 、 filter 等数组方法不适合实现多个Promise串行执行,因为它们都是并行执行函数,它们不会等待前一个函数返回结果后再执行下一个函数。因此,使用这些方法可能会导致Promise对象并行执行,而不是按顺序串行执行它们。 而 reduce 方法可以用来串行执行多个Promise,因为 reduce 方法可以将一个函数的返回结果作为下一个函数的参数,因此,我们可以将每个Promise的返回值作为下一个Promise的参数,使它们按顺序一个接一个地执行。
进一步封装返回执行的结果:
function serialPromise(promiseArray) {
return promiseArray.reduce((promiseChain, currentPromise) => {
return promiseChain.then((chainResults) => {
return currentPromise().then((currentResult) => {
return [...chainResults, currentResult];
});
});
}, Promise.resolve([]));
}
2
3
4
5
6
7
8
9
🌙 使用for wait...of (opens new window)实现
for await...of
语句创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象
备注:
for await...of
不适用于不是异步可迭代的异步迭代器。
async function serialPromise(promiseArr) {
let result = [];
for await (const p of promiseArr) {
result.push(await p());
}
return result;
}
serialPromise(arr).then(res => console.log(res)) // [1,2,3]
2
3
4
5
6
7
8
9
🌙 优化版
上述代码无法处理错误, 我们可以使用如下方式处理:
export async function serialPromise1(promiseArr: (Promise<any> | (() => Promise<any>))[], callback: (result: any) => void) {
let resolves = [];
while(promiseArr.length > 0) {
let p = promiseArr.shift();
// 创建新的 Promise, 此时已经把结果放到了 newP 中
let newP = new Promise((resolve, reject) => {
if(p instanceof Promise) {
p.then((res: unknown) => {
// 成功
resolve(res)
}).catch((e: any) => {
// 失败
resolve(e)
})
}
if(typeof p === 'function') {
p().then((res: unknown) => {
// 成功
resolve(res)
}).catch((e: any) => {
// 失败
resolve(e)
})
}
})
resolves.push(newP)
}
// 串行执行结束后,将结果放进新的Promise 中,并执行回调
return Promise.all(resolves).then((arr) => {
callback(arr)
return arr
});
}
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
32
33
34
35
测试如下:
import { test, expect } from 'vitest';
test('[serialPromise1] - Sequential Processing 2', async () => {
const promises = [
Promise.resolve(1),
Promise.reject(2),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 500);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
reject(4);
}, 200);
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5);
}, 600);
}),
function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(6);
}, 400);
});
},
function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(7);
}, 100);
});
}
];
// const results: number[] = [];
const callback = (result: any[]) => {
console.log('Result:', result);
expect(result.map((r: { data: any; }) => r.data)).toEqual([1, 2, 3, 4, 5, 6, 7]);
};
await serialPromise1(promises, callback);
});
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
打印结果:
Result: [
{ data: 1, type: 'success' },
{ data: 2, type: 'error' },
{ data: 3, type: 'success' },
{ data: 4, type: 'error' },
{ data: 5, type: 'success' },
{ data: 6, type: 'success' },
{ data: 7, type: 'success' }
]
2
3
4
5
6
7
8
9