两种实现方式异步任务调度器 | 创作者训练营

1,188 阅读1分钟

如题,实现一个异步任务调度器 Scheduler,可以按需实现并发数量控制。

思路梳理

首先使用 Scheduler.addTask 持续添加异步任务。按照条件添加到对应列表,doingList 执行列表 waitingList 缓存列表。

其次每成功执行一次 doingList,需要从waitingList 获取新任务并且更新队列。这里的核心点是:异步任务完成后如何通知调度器。有两种方式可以实现:

  • 第一种使用 Promise.resolve() 一路传递状态;
  • 第二种异步任务完成后手动调用方法通知 Scheduler;

最后循环执行第二步,直到 doingList 为空。

Promise 方式

class Scheduler {
    constructor(num) {
        this.num = num;
        this.doingList = [];
        this.waitingList = [];
    }
    addTask(task) {
        return new Promise((resolve, reject) => {
            task.resolve = resolve;
            task.reject = reject;
            if (this.doingList.length < this.num) {
                this.doingList.push(task);
                this.performTask(task);
            } else {
                this.waitingList.push(task);
            }
        });
    }
    performTask(task) {
        task().then(() => {
            task.resolve();
        }, task.reject).then(() => {
            console.log('当前并行任务数', this.doingList.length);
            const index = this.doingList.indexOf(task);
            this.doingList.splice(index, 1);
            if (this.waitingList.length) {
                const nextTask = this.waitingList.shift();
                this.doingList.push(nextTask);
                this.performTask(nextTask);
            }
        });
    }

}

function createAsyncTask(count) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
            console.log(`执行时间${count}s`);
        }, count * 1000);
    });
}

const scheduler2times = new Scheduler(2);
scheduler2times.addTask(() => createAsyncTask(2)).then(() => { console.log('任务1执行完成'); });
scheduler2times.addTask(() => createAsyncTask(3)).then(() => { console.log('任务2执行完成'); });
scheduler2times.addTask(() => createAsyncTask(1)).then(() => { console.log('任务3执行完成'); });
scheduler2times.addTask(() => createAsyncTask(1)).then(() => { console.log('任务4执行完成'); });
scheduler2times.addTask(() => createAsyncTask(1)).then(() => { console.log('任务5执行完成'); });

手动调用方式

class Scheduler {
    constructor(limit) {
        this.limit = limit;
        this.task = [];
        this.woringCount = 0;
    }

    preform(at) {
        if (this.woringCount < this.limit) {
            this.runner(at);
        } else {
            console.log('limit:', this.limit);
            this.task.push(at);
        }
    }

    runner(at) {
        this.woringCount = this.woringCount + 1;
        console.log('workgingCount:', this.woringCount);
        at();
    }

    complate(id) {
        console.log('finished:', id);
        this.woringCount = this.woringCount - 1;
        console.log('workgingCount:', this.woringCount);
        this.nextTask();
    }

    nextTask() {
        if (!this.task.length && this.woringCount !== 0) {
            console.log('task no reat');
        } else if (this.woringCount === 0) {
            console.log('finish all');
        } else {
            this.runner(this.task.shift());
        }
    }

    addTask(fn) {
        this.task.push(fn);
    }
}

const schedule = new Scheduler(2);

function asyncTask(time) {
    return () => {
        setTimeout(() => {
            console.log(`finish async task: ${time}`);
            schedule.complate(time);
        }, time);
    };
}

const at1 = asyncTask(2000);
const at2 = asyncTask(3000);
const at3 = asyncTask(4000);
const at4 = asyncTask(5000);

schedule.preform(at1);
schedule.preform(at2);
schedule.preform(at3);
schedule.preform(at4);

「 一枚前端学习小透明,努力学习前端知识,同时分享自己对生活的一些思考,欢迎一起讨论交流。如果我的文章对你有帮助,请点个赞,会非常感恩你的鼓励。完」

[两种实现方式异步任务调度器 | 创作者训练营 征文活动正在进行中......]