某跳动面试官:实现一个带并发限制的异步调度器叭。

679 阅读1分钟

思路

思路很重要的一点就是保存promise的状态,不要让它立即resolve。而延迟执行有两种方式:
1.静态函数实现
2.await实现

静态函数

class Scheduler {
    constructor() {
        this.needRunTasks = []
        this.runTasks = []
    }
    add(prmoiseFn) {
        return new Promise((resolve, reject) => {
            //保存Promise状态,现在不能执行
            prmoiseFn.resolve = resolve; 
            if (this.runTasks.length < 2) {
                this.run(prmoiseFn)
            } else {
                this.needRunTasks.push(prmoiseFn)
            }
        })
    }
    run(prmoiseFn) {
        this.runTasks.push(prmoiseFn)
        prmoiseFn().then(() => {
            prmoiseFn.resolve()
            this.runTasks.splice(this.runTasks.indexOf(prmoiseFn), 1) //移除执行后的任务
            if (this.needRunTasks.length > 0) {
                this.run(this.needRunTasks.shift())
            }
        })
    }
}

await

class Scheduler {
    constructor() {
        this.taskNum = 0;
        this.taskQueue = [];
    }


    async add(promiseCreator) {
        //在promise内部把resolve放到任务队列中,只有当resolve被调用,后面的代码才被执行
        if (this.taskNum >= 2) {
            await new Promise((res) => {
                this.taskQueue.push(res)
            })
        }
        this.taskNum++;
        await promiseCreator();
        this.taskNum--;
        if (this.taskQueue.length > 0) {
            //当前任务完成后,如果任务队列里有resolve,那么就调用resolve,之前被堵住的部分就可以得到执行
            this.taskQueue.shift()();
        }
    }
}

Promise单队列

class Scheduler {
            constructor(limit) {
                this.limit = limit;
                this.count = 0;
                this.taskArr = [];
            }

            add(fn) {
                return new Promise((res, rej) => {
                    this.taskArr.push({ fn, res })
                    this.run()
                })
            }

            run() {
                if (this.taskArr.length && this.count < this.limit) {
                    this.count++;
                    let { fn, res } = this.taskArr.shift();
                    fn().then(() => {
                        res()
                        this.count--;
                        this.run()
                    })
                }
            }
        }

测试代码

const scheduler = new Scheduler()

const promiseFn = (time) =>
    new Promise(resolve => setTimeout(resolve, time))

const addTask = (time, order) =>
    scheduler.add(() =>
        promiseFn(time))
        .then(() =>
            console.log(order))
            
addTask(400, 4)
addTask(200, 2)
addTask(300, 3)
addTask(50, 1)

image.png


记录记录!