实现思路
- 我们可以使用一个计数器来记录当前正在执行的请求数量,初始值为0。
- 维护一个请求队列,将所有10个请求放入队列中。
- 每次从队列中取出一个请求执行,同时计数器加1。
- 当一个请求完成(无论成功还是失败),计数器减1,然后从队列中取出下一个请求执行,直到队列为空。
- 为了处理错误,我们可以在每个请求的Promise中使用
.catch
方法捕获错误,并在最终的Promise中统一处理。
代码实现
function asyncTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟异步操作,这里可以替换为实际的异步请求
Math.random() > 0.5? resolve('success') : reject('error');
}, 1000);
});
}
function concurrentControl(tasks, maxConcurrent) {
return new Promise((resolve, reject) => {
let completedCount = 0;
let error = null;
const results = [];
const queue = tasks.slice();
const runningCount = 0;
function next() {
while (runningCount < maxConcurrent && queue.length > 0) {
const task = queue.shift();
task()
.then(result => {
results.push(result);
completedCount++;
if (completedCount === tasks.length) {
resolve(results);
}
next();
})
.catch(err => {
if (!error) {
error = err;
reject(error);
}
next();
});
}
}
next();
});
}
// 示例使用
const tasks = Array.from({ length: 10 }, () => asyncTask);
concurrentControl(tasks, 3)
.then(results => {
console.log('All tasks completed successfully:', results);
})
.catch(error => {
console.log('An error occurred:', error);
});
错误处理
- 在每个请求的Promise中使用
.catch
捕获错误。
- 如果有错误发生,首先检查
error
变量是否已经有值。如果没有,则将当前错误赋值给error
,并调用reject
拒绝最终的Promise。如果error
已经有值,说明之前已经发生过错误,此时只需要调用next
继续处理队列中的下一个请求即可,因为最终的Promise已经被拒绝,后续错误不需要重复处理。这样可以确保在第一个错误发生时,整个并发操作能够及时失败并返回错误信息,同时继续处理队列中的其他请求,保证队列中的所有任务都能得到执行机会。