JavaScript实现带并发限制的异步调度器

 更新时间:2024年03月26日 09:09:59   作者:翰玥  
这篇文章主要为大家详细介绍了如何基于JS实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有N个,感兴趣的小伙伴可以了解下

题目

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

class Scheduler {
  add(promiseCreator) { ... }
  // ...
}

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

const scheduler = new Scheduler(n)
const addTask = (time, order) => {
  scheduler.add(() => timeout(time)).then(() => console.log(order))
}

addTask(1000, '1')  // 任务1
addTask(500, '2') // 任务2
addTask(300, '3') // 任务3
addTask(400, '4')  // 任务4

// 打印顺序是:2 3 1 4

题目分析

假设N为2,也就是保证同时运行的任务有2个。那么在执行addTask 4步操作之后,整体的流程应该是这样的。

  • 起始1、2两个任务开始执行;
  • 500ms时,2任务执行完毕,输出2,任务3开始执行;
  • 800ms时,3任务执行完毕,输出3,任务4开始执行;
  • 1000ms时,1任务执行完毕,输出1,此时只剩下4任务在执行;
  • 1200ms时,4任务执行完毕,输出4;

为什么会出现这样的结果?我们来具体分析一下

首先连续执行了4次addTask,由于只能同时运行的任务有2个,所以,任务1和任务2将直接运行,任务1将在1000ms之后运行,任务2将在500ms之后运行,所以,任务2肯定会比任务1执行的快。当任务2执行完毕之后,输出2。紧接着执行任务3,此时任务1执行也就经过了500ms,还有500ms没有执行完,而任务3只需要300ms就执行完毕,所以任务3也会比任务1执行的快。又过了300ms(共计过了800ms)任务3执行完毕,输出3。任务4开始执行,任务4需要400ms执行完毕,而任务1目前只需要200ms,所以任务1会比任务4先执行,200ms之后(共计1000ms)任务1执行完毕,输出1,在过了200ms(共计1200ms),任务4执行完毕,输出4。

下面我们用图来表示一下

知道了这道题目具体要干啥了,下面就来看看代码是如何实现的

代码实现

直接上完整代码好了~

class Scheduler {
  constructor(max) {
    this.max = max;
    this.count = 0; // 用来记录当前正在执行的异步函数
    this.queue = new Array(); // 表示等待队列
  }
  async add(promiseCreator) {
    /*
        此时count已经满了,不能执行本次add需要阻塞在这里,将resolve放入队列中等待唤醒,
        等到count<max时,从队列中取出执行resolve,执行,await执行完毕,本次add继续
        */
    if (this.count >= this.max) {
      await new Promise((resolve, reject) => this.queue.push(resolve));
    }

    this.count++;
    let res = await promiseCreator();
    this.count--;
    if (this.queue.length) {
      // 依次唤醒add
      // 若队列中有值,将其resolve弹出,并执行
      // 以便阻塞的任务,可以正常执行
      this.queue.shift()();
    }
    return res;
  }
}

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

const scheduler = new Scheduler(2);

const addTask = (time, order) => {
  //add返回一个promise,参数也是一个promise
  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

这块代码中我们主要加了add部分。

首先我们来分析一下 Scheduler这个类。max表示同时可以执行任务的最大数量。count用来记录当前正在执行的异步函数。每次addTask都会通过scheduler.add添加一个异步任务。

进入add函数中,首先需要做的事情是当前已经正在执行的任务有没有到达最大的任务数。

如果没有达到最大的任务数(比如刚开始的加入任务一和任务二,此时任务是空的),每次执行await promiseCreator();这一步的时候,使用async await,当promiseCreator没有执行完毕的时候,会阻塞后面的任务。所以当前两个任务被addTask加入的时候,执行add的时候,都会阻塞后面的任务。而我们的四个任务连续被加入的。当add任务三和任务四的时候,发现此时count已经满了,所以需要阻塞在这里,将resolve放入队列中等待唤醒吗,具体什么时候被唤醒呢?当前面的任务有任何一个执行完毕之后,就可以被唤醒。这里使用queue来维护resolveadd任务三和任务四的时候,会先后给queue推入这两个promiseresolve

经过500ms,任务二会先执行完毕,也就是await promiseCreator();执行完毕之后,打印2,然后继续之后后续的代码,此时从queue里面将第一个resolve弹出,并执行。执行之后,任务3也就不再阻塞了,将继续执行await promiseCreator();.

再经过300ms任务三先执行完毕之后(任务还在继续执行中),打印3,然后继续之后后续的代码,此时从queue里面将resolve弹出,并执行。执行之后,任务4也就不再阻塞了,将继续执行await promiseCreator();.

再经过200ms任务一终于执行完毕之后,打印1,然后继续之后后续的代码,此时queue里面已经是空的了

再经过200ms任务四执行完毕,打印4

到此这篇关于JavaScript实现带并发限制的异步调度器的文章就介绍到这了,更多相关JavaScript异步调度器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Javascript 判断 object 的特定类转载

    Javascript 判断 object 的特定类转载

    Javascript 判断 object 的特定类转载...
    2007-02-02
  • Google Map API更新实现用户自定义标注坐标

    Google Map API更新实现用户自定义标注坐标

    由于工作需要,又要开始看Google Map API 代码,今天再把我之前的GoogleMap类,又更新了下,加了个简单的用户自定义标注坐标的功能。看看吧(代码没怎么优化,别见笑)
    2009-07-07
  • js事件监听器用法实例详解

    js事件监听器用法实例详解

    这篇文章主要介绍了js事件监听器用法,以实例形式较为详细的分析了javascript事件监听器使用注意事项与相关技巧,需要的朋友可以参考下
    2015-06-06
  • Bootstrap popover 实现鼠标移入移除显示隐藏功能方法

    Bootstrap popover 实现鼠标移入移除显示隐藏功能方法

    下面小编就为大家分享一篇Bootstrap popover 实现鼠标移入移除显示隐藏功能方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • php的派发机制实现方法

    php的派发机制实现方法

    PHP是一种动态类型的编程语言,它支持面向对象编程,在PHP中,派发指在运行时确定要调用的方法或函数的过程,派发机制允许根据实际对象的类型来选择要执行的方法,这种灵活性使得PHP可以实现多态性,本文将给大家介绍php的派发机制是怎么实现的,需要的朋友可以参考下
    2023-10-10
  • 浅谈JavaScript原型链

    浅谈JavaScript原型链

    这篇文章主要为大家详细介绍了JavaScript原型链,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2023-04-04
  • DeviceOne 让你一见钟情的App快速开发平台

    DeviceOne 让你一见钟情的App快速开发平台

    DeviceOne是一个非常先进的App开发平台,使用Javascript 构建原生体验的移动应用程序,DeviceOne主要关注外观和体验,以及和你的应用程序的 UI 交互
    2016-02-02
  • Bootstrap中表单控件状态(验证状态)

    Bootstrap中表单控件状态(验证状态)

    这篇文章主要介绍了Bootstrap中表单控件状态(验证状态) 的相关资料,还给大家介绍了在Bootstrap框架中提供的机制验证效果,非常不错,需要的朋友可以参考下
    2016-08-08
  • Bootstrap CSS布局之按钮

    Bootstrap CSS布局之按钮

    这篇文章主要介为大家详细绍了Bootstrap CSS布局之按钮的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • JavaScript实现动态创建CSS样式规则方案

    JavaScript实现动态创建CSS样式规则方案

    这篇文章主要介绍了JavaScript实现动态创建CSS样式规则方案,本文包含获取样式表、创建样式表、插入规则、添加规则等内容,需要的朋友可以参考下
    2014-09-09

最新评论