题目
实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有N个。
完善下面代码中的 Scheduler 类,使得以下程序能正确输出:
class Scheduler {
add(promiseCreator) { ... }
// ...
}
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler(n)
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// 打印顺序是:2 3 1 4
核心思路:考察 Promise
知识点;当任务数超过规定任务数,创建微任务
进行等待。
代码实现
class Scheduler {
constructor(max) {
this.max = max;
this.count = 0; // 当前执行中的异步操作
this.queue = new Array(); // 记录当前的执行数组
}
async add(promiseCreator) {
// count >= max 时,此时先不直接执行,将当前异步操作存储起来,当count满足时,再去执行
// Promise.then的链式调用 new Promise((resolve) => { setTimeout(() => {}, 10000}).then xxxx
if (this.count >= this.max) {
/** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */
await new Promise((resolve, reject) => {
this.queue.push(resolve);
});
}
/** queue某一项resolve()后会从这儿往下走 */
this.count++;
let res = await promiseCreator();// 执行timeout(time)
this.count--; // 执行完1轮才往下走到这儿
if (this.queue.length) {
this.queue.shift()();//删除queue数组第一项并执行resolve()
}
return res;
}
}
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler(n) // 任务2个=>n即为2
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
运行结果如下:
通过输出结果分析代码执行顺序
class Scheduler {
constructor(max) {
this.max = max
this.count = 0
this.queue = new Array()
}
async add(promiseCreator) {
if (this.count >= this.max) {
await new Promise((resolve, reject) => {
this.queue.push(resolve)
})
}
this.count++
const res = await promiseCreator()
this.count--
if (this.queue.length) {
this.queue.shift()()
}
console.log('res: ', res)
return res
}
}
const timeout = (time) => new Promise(resolve => {
console.log('100')
setTimeout(resolve, time)
})
const scheduler = new Scheduler(2)
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => {console.log(order); return 'timeout'})
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
打印结果:
100
100
res: undefined
100
2
res: undefined
100
3
res: undefined
1
res: undefined
4
输出结果分析
- Part 1:
(1)addTask1000、addTask500:
走两次到这儿
this.count++
const res = await promiseCreator(); 都输出’100’,先打印2个'100'
(2)addTask300、addTask400:
/** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */
await new Promise((resolve, reject) => {
this.queue.push(resolve);
}); - Part 2:
(3)500ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(4)∵this.queue.shift()()即resolve()是同步代码,
addTask300走到这儿
this.count++
const res = await promiseCreator();
∴先打印下一个'100'
再return res打印'2'
- Part 3:
(5)接下来同理,300ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(6)∵this.queue.shift()()即resolve()是同步代码,
addTask400走到这儿
this.count++
const res = await promiseCreator();
∴先打印下一个'100'
再return res打印'3'
- Part 4:
(7)1000ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(8)没有下一个’100’了,return res打印'1'
; - Part 5:
(9)400ms的timeout执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
;
(10)没有下一个’100’了,return res打印'4'
;