🌙 并行执行
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