实现一个Scheduler类,使下面的代码能正确输出。
const timeout = (time, value) => new Promise(resolve => {
setTimeout(() => resolve(value), time)
})
const scheduler = new Scheduler(2)
const addTask = (time, order, value) => {
return scheduler.add(() => timeout(time, value))
.then((value) => {
console.log(order)
return value;
})
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// output: 2 3 1 4
解题思路
- 观察题目
- timeout 传递时间和值两个参数,返回一个promise,promise中有一个执行函数,一定时间之后执行resolve。
- scheduler 通过 new Schedule 产生一个调度的对象。
- addTask 传递 时间、编号、返回值三个参数,返回调度对象.add 方法执行的结果。 add对象传递 timeout函数进去,并且答应序号和 timeout函数传递的值。
- 执行顺序是 1、2、3、4 最后的结果是 2、3、1、4
- 推测
- 根据执行的顺序和结果的顺序推测,构造函数里传入的是 限制最多同时执行任务的数量。
1(1000)、2(500)同时执行,2(500)先执行完毕,然后执行 3(300),3执行完毕后,执行4(400),然后1执行完毕,最后4执行完毕。
- 伪代码
class Scheduler {
constructor(最大任务数) {
维护一个队列存放不立即执行的任务。
维护当前执行的任务数
维护最大任务数
}
add(任务) {
if 当前任务数 > 最大任务数 就用await阻塞住,
push resolve到维护的数组里,执行完毕后解除阻塞。
任务数+1 执行任务 执行任务(用await阻塞,任务执行完毕后才解除阻塞)
任务数-1 检查数组如果有不立即执行的任务就吐出来。
}
}
- 答案
class Scheduler {
// 构造函数
constructor(maxJob) {
this.maxJob = maxJob; // 最大任务数
this.queue = []; // 维护的队列
this.currentJob = 0; // 当前任务数
}
async add(callback) {
// 当前任务数大于最大任务数时阻塞,否则执行
if(currentJob > maxJob) {
await new Promise(resolve => this.queue.push(resolve))
}
this.currentJob++;
const result = await callback();
this.currentJob--;
if(queue.length !== 0) {
// 从队列里取出先push进的 resolve 执行取消阻塞
this.queue.unshift()();
}
return result;
}
}