题目:
实现一个 SuperTask类,其至少具有 add 方法和最大并发数 max,该 add 方法接收函数(返回值为 promise),当当前执行的任务数小于设定值 max 时,立即执行,大于 max,则等待任务空闲时执行该任务,模版代码如下:
function timeout(time) {
return new Promise((reslove) => {
setTimeout(() => {
reslove()
}, time);
})
}
const superTask = new SuperTask()
function addTask(time, name) {
superTask
.add(() => timeout(time))
.then(() => { console.log(`任务${name}完成`); })
}
addTask(10000, 1) // 10000ms后输出:任务1完成
addTask(5000, 2) // 5000ms后输出:任务2完成
addTask(3000, 3) // 8000ms后输出:任务3完成
addTask(4000, 4) // 12000ms后躺出:任务4完成
addTask(5000, 5) // 15000ms后输出: 任务5完成
这个题目在我遇到的面试中,非常高频,在面试的场景下第一次遇到这个题,不免手忙脚乱,但是实际上逻辑非常简单,设置当前执行任务数 cur,并设计一个数组(模拟队列)。每次添加任务或者任务执行完,都去执行如下逻辑:
- 判断 cur 是否小于 max
- 小于 max,cur++, 第一个任务出队并执行,并在执行结束后,cur–,再次执行相同逻辑
- 大于 max,不做处理
答案如下:
class SuperTask{
constructor(num = 2) {
this.max = num; // 记录最大并发数量
this.cur = 0; // 记录当前在执行中的任务数量
this.tasks = []; // 保存任务
}
add(task) {
return new Promise((reslove, reject)=>{
this.task.push({
task,
reject,
reslove
}); // 每次添加,就是往队列尾部增加任务
this._run() // 并执行 run 方法
})
}
_run() {
// 判断是否还有任务,以及当前执行中的任务是否小于并发数量
while (this.tasks.length && this.cur < this.max) {
// 取出队列第一个任务
const {task, reslove, reject} = this.tasks.shift();
// 记录执行中任务数量 +1
this.cur++;
// 执行任务
task().then(reslove, reject).finally(() => {
// 任务结束后,执行中任务数量 -1
this.cur--;
// 并执行同样的逻辑
this._run();
});
}
}
}
应用场景
我们实现了一个简单的异步并发任务控制器类,它可以帮助我们管理和执行一系列返回promise对象函数。那么,在实际开发中,这种工具有哪些应用场景呢?
- 当我们需要对多个网络请求进行批量处理时,例如下载多张图片、上传多个文件、获取多条数据等。
- 当我们需要对多个文件进行批量操作时,例如读取多个文件内容、写入多个文件数据、删除多个文件等。
- 当我们需要对多个定时器进行批量管理时,例如设置多个倒计时、取消多个倒计时等。