背景
今天在《前端技术江湖》公众号看到一片文章:头条前端笔试题 - 实现一个带并发限制的promise异步调度器,虽然运行结果相同,但是作者在实现的过程中对方法的定义都进行修改了,因此笔者按照自己的方法实现了这个异步调度器。
题目描述
JS 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个。完善下面代码中的 Scheduler 类,使得以下程序能正确输出。
class Scheduler {
add(promiseCreator) {/*...*/}
// ...
}
const timeout = (time) =>
new Promise((resolve) => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// output: 2 3 1 4
// 一开始,1,2两个任务进入队列
// 500ms时,2完成,输出2,3进入执行队列
// 800ms时,3完成,输出3,4进入执行队列
// 1000ms时,1完成,输出1
// 1200ms时,4完成,输出4
题目分析
- 最后执行的是
addTask方法,那我们首先从这个方法入手。函数执行体中执行了scheduler.add(fn),这个方法后面紧接着then方法,意味着scheduler.add返回的是一个Promise对象。 - 按照题意,当前最多只能有两个任务在运行,那么我们在
Scheduler类中定义一个任务队列tasks属性,定义一个当前正在运行的任务数量runningTaskCount属性,当runningTaskCount小于2 时,马上执行add(promiseCreator)中的promiseCreator函数,否则当某一个任务执行完后再执行一个新的任务。
直接上代码了
class Scheduler {
constructor() {
this.tasks = []
this.runningTaskCount = 0
this.resolveArr = []
}
add(promiseCreator) {
this.tasks.push(promiseCreator)
return new Promise((resolve) => {
this.resolveArr.push(resolve)
this.run()
})
}
run() {
if (this.runningTaskCount < 2 && this.tasks.length > 0) {
this.runningTaskCount++
const resolveFn = this.resolveArr.shift()
const task = this.tasks.shift()
task().then(() => {
this.runningTaskCount--
resolveFn()
this.run()
})
}
}
}
const timeout = (time) =>
new Promise((resolve) => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')