并发任务控制
大约 3 分钟
并发任务控制
在开发当中,我们可能会遇到页面上存在许多并发任务的情况,比如说:许多个获取服务器资源的远程请求,其他一些异步操作等,如果对这些并发任务处理不当,就可能会导致资源的占用。这时我们就需要对这些并发任务加以控制了。
控制并发
当需要控制多个异步任务的并发执行时,可以使用任务控制器。这个控制器可以限制同时进行的异步任务数量,保证队列中的任务按照顺序执行(先添加的任务先执行,后添加的任务后执行),并统一处理所有任务返回的 promise 对象。
一下是实现方式之一:
class TaskController {
constructor(maxConcurrent) {
this.maxConcurrent = maxConcurrent; // 最大并发数
this.currentConcurrent = 0; // 当前并发数
this.taskQueue = []; // 任务队列
}
add(task) {
this.taskQueue.push(task); // 将任务函数加入队列
this.run(); // 尝试执行任务
}
run() {
while(this.currentConcurrent < this.maxConcurrent && this.taskQueue.length > 0) {
const task = this.taskQueue.shift(); // 取出队列中的第一个任务函数
this.currentConcurrent++; // 增加当前并发数
task()
.then((result) => {
console.log(result); // 如果成功,打印结果(或者做其他操作)
})
.catch((error) => {
console.error(error); // 如果失败,打印错误(或者做其他操作)
})
.finally(() => {
// 不管成功还是失败,都要减少当前并发数,并执行下一个任务(递归调用)
this.currentConcurrent--;
this.run();
});
}
}
}
// 示例用法
const controller = new TaskController(2); // 创建一个异步任务控制器实例,最大并发数为2
// 模拟异步任务
const successTask = (id) => () => new Promise((resolve) => {
setTimeout(() => resolve(id), 1000);
});
const failTask = (id) => () => new Promise((_, reject) => {
setTimeout(() => reject(id*-1), 1000);
});
// 添加一些异步任务到控制器中
controller.add(successTask(1));
controller.add(failTask(2));
controller.add(successTask(3));
controller.add(failTask(4));
controller.add(successTask(5));
中断与恢复
上面的控制器有了基本的控制并发任务数量的功能,还缺少一个任务中断的功能,以下是实现任务中断功能的改进代码实现:
class TaskController {
constructor(maxConcurrent) {
this.maxConcurrent = maxConcurrent; // 最大并发数
this.currentConcurrent = 0; // 当前并发数
this.taskQueue = []; // 任务队列
this.isRunning = false; //是否正在执行并发任务
}
add(tasks) {
if (typeof tasks === 'object' && tasks.length > 0) {
this.taskQueue.push(...tasks);
} else {
this.taskQueue.push(tasks); // 将任务函数加入队列
}
console.log(this.taskQueue)
this.run(); // 尝试执行任务
}
run() {
if (this.isRunning) {
return
}
this.isRunning = true
while (this.currentConcurrent < this.maxConcurrent && this.taskQueue.length > 0) {
const task = this.taskQueue.shift(); // 取出队列中的第一个任务函数
this.currentConcurrent++; // 增加当前并发数
task()
.then((result) => {
console.log(`任务${result}开始`)
console.log(result); // 如果成功,打印结果(或者做其他操作)
})
.catch((error) => {
console.log(`任务${error}开始`)
console.error(error); // 如果失败,打印错误(或者做其他操作)
})
.finally(() => {
console.log(`任务结束`)
// 不管成功还是失败,都要减少当前并发数,并执行下一个任务(递归调用)
this.currentConcurrent--;
if (!this.isRunning) {
//如果外部手动中止任务,就停止执行
return
}
//当前任务执行完成后,恢复 isRunning 状态
this.pause();
//继续执行队列中的下一个任务
this.run();
});
}
}
pause() {
this.isRunning = false //中断任务执行
}
}
// 示例用法
const controller = new TaskController(2); // 创建一个异步任务控制器实例,最大并发数为2
// 模拟异步任务
const successTask = (id) => () => new Promise((resolve) => {
setTimeout(() => resolve(id), 1000);
});
const failTask = (id) => () => new Promise((_, reject) => {
setTimeout(() => reject(id*-1), 1000);
});
// 添加一些异步任务到控制器中
controller.add(successTask(1));
controller.pause()
controller.add(failTask(2));
controller.add(successTask(3));
controller.pause()
controller.add(failTask(4));
controller.add(successTask(5));