题目内容
任务调度,实现一定任务的并发(面试的时候要求的2个任务)
function timeout(time) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 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后输出 任务1完成
addTask(3000, 3); // 8000ms后输出 任务3完成
addTask(4000, 4); // 11000ms后输出 任务4完成
addTask(5000, 5); // 15000ms后输出 任务5完成
基础知识
这个题需要的基础知识相对比较简单
- 构造函数
- Promsie
题目分析
- 从使用方法可知,
SuperTask
是一个构造函数。 SuperTask
有add
的方法,可以链式调用then
,那么返回值是promise
。- 因为是固定并发数量,所以
SuperTask
中需要有属性保存最大并发数,以及当前正在执行的任务数量。 addTask
可以不断被调用,但是我们并发是固定的,所以SuperTask
中需要有属性保存总的任务。- 我们保存任务的时候,不能让
task
执行,所以需要封装一下,保证我们执行任务的时候再执行内部的内容。
实现
function SuperTask(maxTaskNumber = 2) {
// 保存需要执行的任务
this.tasks = [];
// 正在执行的任务数量
this.runTaskNumber = 0;
// 最大的同时(并发)执行的任务数量
this.maxTaskNumber = maxTaskNumber;
}
SuperTask.prototype.add = function(fn) {
// 根据使用方法,推测出add函数返回的是一个Promise对象
return new Promise(resolve => {
// 处理任务,任务执行完成后,需要改变 add 返回的promise的状态
// 保证任务执行完成后,触发add函数后的 then 方法
const task = () => {
// 从题目可知fn的返回值时promise对象
// 因为我们需要根据task执行完成后,再执行后续任务,所以这儿需要把fn的执行结果返回
return fn.call(null).then(() => {
resolve();
})
}
// 保存任务
this.tasks.push(task);
// 执行任务
this.run();
})
}
SuperTask.prototype.run = function() {
// 当前正在执行的任务 小于 并发数量 且 还有需要执行的任务时
while(this.runTaskNumber < this.maxTaskNumber && this.tasks.length) {
// 正在执行的任务数+1
this.runTaskNumber++;
// 获取当前最先被保存在总任务中的任务
const task = this.tasks.shift();
task().then(() => {
// 任务执行完成后,正在执行的任务 -1
this.runTaskNumber--;
// 开始下一轮的执行任务
this.run();
})
}
}