并发控制
- 使用
Promise.allSettled
和队列
- 创建一个任务队列,将所有异步任务放入队列中。
- 维护一个正在执行的任务数组,同时执行的任务数量不超过设定的并发数。
- 当有任务完成时,从正在执行的任务数组中移除,并从任务队列中取出新的任务执行,直到任务队列耗尽。
- 最后使用
Promise.allSettled
等待所有任务(包括已经完成和正在执行的)都结束,统一处理结果。
示例代码如下:
function limitConcurrentTasks(tasks, limit) {
return new Promise((resolve, reject) => {
const results = [];
let completedCount = 0;
const executingTasks = [];
const executeNext = () => {
while (executingTasks.length < limit && tasks.length > 0) {
const task = tasks.shift();
const promise = task();
executingTasks.push(promise);
promise.then((res) => {
results.push({ status: 'fulfilled', value: res });
}).catch((err) => {
results.push({ status:'rejected', reason: err });
}).finally(() => {
completedCount++;
const index = executingTasks.indexOf(promise);
if (index!== -1) {
executingTasks.splice(index, 1);
}
if (completedCount === tasks.length + executingTasks.length) {
resolve(results);
} else {
executeNext();
}
});
}
};
executeNext();
});
}
// 使用示例
const tasks = [
() => new Promise((resolve) => setTimeout(() => resolve(1), 1000)),
() => new Promise((resolve) => setTimeout(() => resolve(2), 1500)),
() => new Promise((resolve) => setTimeout(() => resolve(3), 500))
];
limitConcurrentTasks(tasks, 2).then((results) => {
console.log(results);
});
- 使用
async/await
和循环
- 同样先将所有任务放入数组,通过循环和
await
来控制并发数量。
- 每次循环中创建一定数量的任务,使用
Promise.all
等待这些任务完成,然后再进行下一轮循环,直到所有任务处理完毕。
- 示例代码:
async function limitConcurrentTasks2(tasks, limit) {
const results = [];
for (let i = 0; i < tasks.length; i += limit) {
const currentTasks = tasks.slice(i, i + limit);
const currentResults = await Promise.all(currentTasks.map(task => task()));
results.push(...currentResults);
}
return results;
}
// 使用示例
const tasks2 = [
() => new Promise((resolve) => setTimeout(() => resolve(1), 1000)),
() => new Promise((resolve) => setTimeout(() => resolve(2), 1500)),
() => new Promise((resolve) => setTimeout(() => resolve(3), 500))
];
limitConcurrentTasks2(tasks2, 2).then((results) => {
console.log(results);
});
处理任务竞争关系(获取最先完成的任务结果)
- 使用
Promise.race
Promise.race
方法接收一个 Promise 数组,返回一个新的 Promise。
- 这个新的 Promise 会在数组中的任何一个 Promise 被解决(resolved)或被拒绝(rejected)时,立刻以相同的状态被解决或被拒绝。
- 示例代码:
const task1 = new Promise((resolve) => setTimeout(() => resolve('Task 1'), 1500));
const task2 = new Promise((resolve) => setTimeout(() => resolve('Task 2'), 1000));
const task3 = new Promise((resolve) => setTimeout(() => resolve('Task 3'), 2000));
Promise.race([task1, task2, task3]).then((result) => {
console.log(result); // 输出 'Task 2',因为它最先完成
});
- 手动实现竞争逻辑
- 可以通过给每个任务添加一个定时器来模拟竞争,先完成的任务会触发对应的回调。
- 示例代码:
function raceTasks(tasks) {
return new Promise((resolve, reject) => {
tasks.forEach(task => {
task().then(resolve).catch(reject);
});
});
}
// 使用示例
const taskA = () => new Promise((resolve) => setTimeout(() => resolve('Task A'), 1500));
const taskB = () => new Promise((resolve) => setTimeout(() => resolve('Task B'), 1000));
const taskC = () => new Promise((resolve) => setTimeout(() => resolve('Task C'), 2000));
raceTasks([taskA, taskB, taskC]).then((result) => {
console.log(result); // 输出 'Task B',因为它最先完成
});