面试题:JS怎么实现并发控制任务执行呢?
题目
给你一段如下代码,要求我们在调用addTask函数时,要求我们有多个任务队列,使我们可以同时执行多个函数。
例如:我们给addTask添加了五个任务,任务1需要 10s、任务2需要 5s、任务3需要3s、 任务4需要4s、 任务5需要5s。我们现在有两个任务队列去执行这个五个任务,需要在5s执行完任务2, 8s执行完任务3,10秒执行完任务1, 12s执行完任务4, 15s执行完任务5。
function timeout(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, time)
})
}
const superTask = new SuperTask(2)
function addTask(time, name) {
superTask
.add(() => timeout(time))
.then(() => {
console.log(`任务${name}完成`);
})
}
addTask(10000, 1) // 10000 1
addTask(5000, 2) // 5000 2
addTask(3000, 3) // 8000 3
addTask(4000, 4) // 12000 4
addTask(5000, 5) // 15000 5
思路
首先,我们先要明白这道题目的意思,利用JS中 promise 异步处理的思想,维护出两个任务队列,分别用两个任务队列同时执行任务1和任务2, 根据任务执行完的先后,改变各自任务的promise状态,执行.then中的回调函数。如果还有任务3,则看哪个任务先执行完,将任务3添加至任务与队列。依此类推,直到全部执行完。
关键步骤
如果我们想达到该题目的效果,有如下九步关键步骤:
1. 定义SuperTask类,接收任务队列的个数
2. 在SuperTask类中定义一个确定正在执行的任务个数
3. 在SuperTask类中定义一个任务队列来承装任务
4. 在SuperTask类中定义一个函数来向任务队列添加任务
5. 在SuperTask类中定义一个函数来执行任务队列的任务
6. 添加任务时,需要将任务和任务状态都添加到任务队列中(**同时我们还要返回出一个promise对象**)
7. 添加完任务后,需要调用执行任务函数执行在任务队列头部的任务,同时增加正在执行的任务个数
8. 当该任务执行完后,改变该任务的promise状态,同时减少正在执行的任务个数
9. 如果任务队列不为空,递归执行任务函数执行任务队列中的其他任务
具体实现
class SuperTask { // 步骤一
constructor(paralleCount = 2) {
this.paralleCount = paralleCount;
this.runningCount = 0; // 步骤二
this.tasks = []; // 步骤三
}
add(task) { // 步骤四
return new Promise((resolve,reject) => {
this.tasks.push({ // 步骤六
task,
resolve,
reject
});
this._run(); // 步骤七
})
}
_run() { // 步骤五
if(this.tasks.length && this.runningCount < this.paralleCount) {
this.runningCount++;
const { task,resolve,reject } = this.tasks.shift();
task().then(resolve,reject).finally(res => { // 步骤八
this.runningCount--;
this._run(); // 步骤九
})
}
}
}
效果:
由此,我们就完整的写出了一个可以控制JS并发任务执行的类,同时我们还可以控制任务队列的个数。
总结
不难看出,我们实现js并发控制任务执行
就是很巧妙的借助了利用Promise.then
微任务的特性,通过控制promise状态的改变, 来控制.then中回调函数执行的时间,同时借助promise异步执行的特性同时执行多个任务。
转载自:https://juejin.cn/post/7210285753351831612