面试:如何实现一个请求的并发控制

67 阅读1分钟

话不多说,我们直接上代码

class TaskManager {
    constructor(max) {
        // 限制最大数量
        this.max = max;
        // 用来保存请求任务
        this.list = [];
        // 当前正在执行的请求数量
        this.pending = 0;
    }

    run() {
        // 从任务队列取出头部任务
        let fn = this.list.shift();
        // 判断任务是否存在
        if (fn) {
            // 正在执行的任务数量+1
            this.pending++
            // 无论请求成功还是失败,都需要执行下一个任务,使用finally保证下一个任务执行
            fn().finally(() => {
                // 执行完成后,数量需要-1
                this.pending--
                // 重复上述操作,递归
                this.run()
            })
        }
    }

    start() {
        // 如果当前正在执行任务小于最大现在,并且任务队列不为空
        while (this.pending < this.max && this.list.length) {
            this.run()
        }
    }

    add(...args) {
        // 向任务队列中塞入任务
        this.list.push(...args);
        // 每次添加任务,都需要运行一次启动
        this.start();
    }
}

let a = new TaskManager(3)
console.time(); // 用来记录任务执行时间
// 模拟一下请求
function f(ms,index) {
    return function () {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(`task ${index} is end`)
                console.timeLog(); // 用来记录任务执行时间
                resolve()
            }, ms)
        })
    }
}

// 这里添加了3个任务,并且在任务二中又添加了2个任务。用来模拟多次添加任务,是否可以正常执行
a.add(f(1000,1), function (){
    a.add(f(4000,4))
    a.add(f(4000,5))
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(`task 2 is end`)
            console.timeLog();
            resolve()
        }, 2000)
    })
})
a.add(f(6000,6),f(7000,7))

看下任务执行结果,符合预期。 image.png