面试题-控制最大并发数(字节原题)

1,840 阅读1分钟

题目:

JavaScript 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个。完善代码中 Scheduler类,使得以下程序能正确输出。

需要注意的点:

  • add 函数后面有个.then 所以add函数是一个Promise对象

实现步骤:

  1. 因为add函数后面有个 .then ,所以在add函数里面我们需要return Promise

  2. 我们需要创建两个list,tasks 和 usingTask,usingTask是正在执行的任务队列,最多两个。taks是等待执行的任务队列

  3. 我们在add函数内return Promise之后,我们需要给当前函数 promiseCreator添加 resolve,用于在执行完之后,就是在then函数内跳出Promise

  4. 前面的步骤是先判断 usingTask 的长度是否小于2,小于2就添加到usingTask任务队列里,并直接执行。如果大于2,就先添加到tasks任务队列里,等待添加

  5. 我们在添加到usingTask 里之后,可以直接执行,执行好之后,也就是在then方法里,我们需要做三个事情

  6. 我们先使用 promiseCreator.resolve() 因为我们return 的是Promise对象,所以需要resolve

  7. 既然执行完了,就不需要在占usingTask 的位置,将其删除

  8. 最后将 tasks内的任务添加到 usingTask 内,并执行。因为是队列,所以我们需要调用 shift方法 

实现代码:

class Scheduler {
    constructor() {
        this.tasks = [], // 待运行的任务
        this.usingTask = [] // 正在运行的任务
    }
    // promiseCreator 是一个异步函数,return Promise
    add(promiseCreator) {
        return new Promise((resolve, reject) => {
            promiseCreator.resolve = resolve
            if (this.usingTask.length < 2) {
                this.usingRun(promiseCreator)
            } else {
                this.tasks.push(promiseCreator)
            }
        })
    }
    usingRun(promiseCreator) {
        this.usingTask.push(promiseCreator)
        promiseCreator().then(() => {
            promiseCreator.resolve()
            let index = this.usingTask.findIndex(promiseCreator)
            this.usingTask.splice(index, 1)
            if (this.tasks.length > 0) {
                this.usingRun(this.tasks.shift())
            }
        })
    }
}
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(400, 4)
addTask(200, 2)
addTask(300, 3)
addTask(100, 1)
// 2, 4, 3, 1