前言
有这样一个场景:前端一次性有100请求要发出去,但是后端一次性只能处理50个请求,这时你会怎么办呢? 在日常开发中,我们经常会遇到需要同时处理多个异步任务的情况,然而,如果同时启动过多的任务会导致资源耗尽或影响性能,一旦任务多了很有可能导致服务器崩溃,因此,合理地控制并发数量是很重要的。本文将介绍如何实现一个简单的并发任务管理器。
正文
延时函数
首先,我们写一个简单的延时函数,它返回一个Promise,以便我们可以使用它来模拟异步任务。
function timeout(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, time);
});
}
这里,timeout
函数接收一个参数 time
,表示延时的时间。
创建任务管理器类
接下来,我们定义一个名为 SuperTask
的类,它负责管理并发的任务队列。
class SuperTask {
constructor(paralleCount = 2) {
// 设置并发任务的最大数量,默认为 2。
this.paralleCount = paralleCount;
// 初始化一个空数组,用于存储待处理的任务。
this.tasks = [];
// 初始化正在运行的任务数量。
this.runningCount = 0;
}
add(task) {
// 添加一个新的任务到任务列表中。
return new Promise((resolve, reject) => {
// 将任务对象推入任务队列。
this.tasks.push({
// 任务本身
task,
// 当任务完成时调用的函数
resolve,
// 当任务失败时调用的函数
reject
});
// 在添加任务之后,尝试运行任务队列。
this._run();
});
}
_run() {
// 当运行中的任务少于最大并发数且任务列表中有任务时,继续添加任务到运行中。
while (this.runningCount < this.paralleCount && this.tasks.length) {
// 从任务队列中取出第一个任务。
const { task, resolve, reject } = this.tasks.shift();
// 增加正在运行的任务数量。
this.runningCount++;
// 执行任务,并处理其完成或失败的情况。
task().then(resolve, reject).finally(() => {
// 减少正在运行的任务数量。
this.runningCount--;
// 再次尝试运行任务队列。
this._run();
});
}
}
}
代码解释:
- 构造函数:
constructor
方法初始化了SuperTask
类的实例,设置了并发任务的最大数量(默认为 2),并初始化了两个数组:tasks
用于存储等待执行的任务,runningCount
用于记录当前正在运行的任务数量。 - 添加任务:
add
方法接收一个任务作为参数,并将其封装成一个任务对象,包含任务函数、成功回调和失败回调,然后将这个任务对象添加到任务队列中,并尝试运行任务队列。 - 运行任务:
_run
方法用于管理任务的执行,它会检查当前正在运行的任务数量是否小于最大并发数,并且任务队列中还有任务,如果条件满足,则从任务队列中取出一个任务,增加正在运行的任务数量,并执行该任务。任务执行完毕后,减少正在运行的任务数量,并再次尝试运行任务队列。
使用任务管理器
最后,我们创建一个 SuperTask
实例,并添加一些任务来看看它是如何工作的。
const superTask = new SuperTask();
function addTask(time, name) {
// 向任务管理器添加一个任务。
superTask
.add(() => timeout(time)) // 添加一个延时任务。
.then(() => console.log('任务完成', name)); // 任务完成后打印一条消息。
}
// 添加几个不同时间的任务。
addTask(10000, 1);
addTask(2000, 2);
addTask(3000, 3);
addTask(3000, 4);
addTask(6000, 5);
代码解释:
- 创建任务管理器实例:
superTask
是SuperTask
类的一个实例,我们可以通过它来管理任务。 - 添加任务函数:
addTask
函数接收两个参数:time
表示任务的延时时间,name
用于标识任务。它调用superTask.add
方法添加一个任务。 - 添加多个任务:我们添加了五个不同的任务,每个任务有不同的延时时间。
效果:
通过这个简单的并发任务管理器,我们可以有效地控制同时运行的任务数量,避免资源过度消耗,并确保所有任务都能按照预期顺序执行。这对于处理大量异步操作特别有用。
完整代码
最后完整代码奉上:
function timeout(time){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, time);
})
}
class SuperTask{
constructor(paralleCount=2){ //不传就是2
this.paralleCount=paralleCount //并发量
this.tasks=[]
this.runningCount=0 //正在运行的任务量
}
add(task){
return new Promise((resolve, reject) => {
this.tasks.push({ //10
task,
resolve,
reject
})
this._run()
})
}
_run(){ //依次运行tasks中的任务
while(this.runningCount<this.paralleCount && this.tasks.length){
const {task,resolve,reject} =this.tasks.shift()
this.runningCount++
task().then(resolve,reject).finally(()=>{
this.runningCount--
this._run()
})
}
}
}
const superTask=new SuperTask()
function addTask(time,name){
superTask
.add(()=>timeout(time))
.then(()=>console.log('任务完成',name))
}
addTask(10000,1)
addTask(2000,2)
addTask(3000,3)
addTask(3000,4)
addTask(6000,5)
总结
本文到此就结束了,希望对你有所帮助,感谢你的阅读!