Rain120 / Web-Study

日常学习,工作写的笔记
66 stars 109 forks source link

实现一个 Schedule 系列问题 #28

Open Rain120 opened 2 years ago

Rain120 commented 2 years ago

假定有一个请求request与一个限制最多同时3个请求的调度器,要求实现一次最多处理limit个数的请求

// 假定有一个请求request与一个限制最多同时3个请求的调度器,要求实现一次最多处理limit个数的请求
function request(params) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(params), 1000);
    });
}

function Scheduler(limit = 3) {
  // ...
}

const createPromise = Scheduler();
createPromise(1).then(res => console.log(res));
createPromise(2).then(res => console.log(res));
createPromise(3).then(res => console.log(res));
createPromise(4).then(res => console.log(res));
createPromise(5).then(res => console.log(res));
// 1 2 3 4 5
Rain120 commented 2 years ago
function Scheduler(limit = 3) {
    const queue = [];
    let running = 0;

    const run = () => {
        if (queue.length <= 0 || running >= limit) {
            return;
        }

        running++;
        const [args, resolve, reject] = queue.shift();

        request(...args)
            .then(resolve, reject)
            .finally(() => {
                running--;
                run();
            });
    }

    return (...args) => {
        return new Promise((resolve, reject) => {
            queue.push([args, resolve, reject]);
            run();
        });
    }
}
Rain120 commented 2 years ago

实现一个限制并发的异步调度器Scheduler,保证同时运行的任务最多2个

const timeout = time =>
    new Promise(resolve => {
        setTimeout(resolve, time);
    });

class Scheduler {
  // ...
}

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
Rain120 commented 2 years ago
class Scheduler {
    constructor(limit = 2) {
        this.limit = limit;
        this.queue = [];
        this.running = 0;
    }

    add(promise) {
        this.queue.push(promise);

        this.run();
    }

    run() {
        if (this.queue.length <= 0 || this.running >= this.limit) {
            return;
        }

        const task = this.queue.shift();

        if (!task) {
            return;
        }

        this.running++;

        task().finally(() => {
            this.running--;
            this.run();
        });
    }
}
Rain120 commented 2 years ago

并发最多同时处理3个请求,但要求如果全部成功则返回结果的数组,且结果顺序与参数顺序保持一致,如果失败则直接返回失败

function request(params) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(params), 1000);
    });
}

function Scheduler(list, limit = 3) {
  // ...
}

Scheduler([1, 2, 3, 4, 5]).then(console.log);
// output:1 2 3 4 5
Rain120 commented 2 years ago
function Scheduler(list, limit = 3) {
    const queue = list.slice();
    const res = [];

    let running = 0;
    let index = 0;

    return new Promise((resolve, reject) => {
        const run = () => {
            if (queue.length <= 0 || running >= limit) {
                return;
            }

            running++;
            const task = queue.shift();

            request(task)
                .then(
                    value => {
                        res[index++] = {
                            value
                        };

                        if (res.length === list.length) {
                            resolve(res);
                        } else {
                            run();
                        }
                    },
                    reason => {
                        res[index++] = {
                            reason
                        }
                    }
                )
                .catch(reject)
                .finally(() => {
                    running--;
                });
        }

        list.forEach(() => run());
    });
}