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

用JavaScript实现一个带并发限制的异步调度器,保证同时最多运行2个任务,完善代码。

class Scheduler {
  constructor() {
    this._max = 2;
  }
}

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

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

addTask(4000,4);
addTask(2000,2);
addTask(3000,3);
addTask(900,1);

这个场景添加了四个异步任务,如果不控制并发的话,按照执行顺序输出的结果应该是

1
2
3
4

先解释一下原题目中的代码

  1. Scheduler类是需要我们实现的一个调度器类,他帮助我们管理添加的异步任务,做到并发限制。

  2. 也就是比如说,以前我们执行异步任务,是直接在当前环境直接执行Promise,而现在要把Promise任务添加到Scheduler中,让他帮助调度执行Promise,于是就有了addTask方法。

  3. 在addTask中,通过Scheduler的add方法,将异步任务扔进Scheduler中。往下看,add方法后面跟着.then,说明add应该返回一个Promise。

  4. 因为add会返回Promise且直接.then执行异步任务,说明在add方法里帮我们判断了异步任务数量是否超出限制,并告诉我们该执行哪个任务。

  5. 那么接下来的目的就很明确了,编写Scheduler类,最重要的就是add方法的实现。

结果代码:

class Scheduler {
  constructor() {
    this._max = 2;
    this.unwork = [];
    this.working = [];
  }

  add(asyncTask) {
    return new Promise((resolve) => {
      asyncTask.resolve = resolve;
      if(this.working.length < this._max) {
        this.runTask(asyncTask);
      } else {
        this.unwork.push(asyncTask);
      }
    })
  }

  runTask(asyncTask) {
    this.working.push(asyncTask);
    asyncTask().then(() => {
      asyncTask.resolve();      //asyncTask异步任务完成以后,再调用外层Promise的resolve以便add().then()的执行
      var index = this.working.indexOf(asyncTask);
      this.working.splice(index,1);   //从正在进行的任务队列中删除
      if(this.unwork.length > 0) {
        this.runTask(this.unwork.shift());  
      }
    })
    
  }
}

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

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

addTask(4000,4);
addTask(2000,2);
addTask(3000,3);
addTask(900,1);

运行结果是

2
4
1
3

add方法中最重要的就是根据是否超过异步任务数量做不同的处理。

首先add方法return的Promise肯定不是直接扔进来的asyncTask,而是再一次Promise封装过的asyncTask,为什么呢?

return asyncTask以后,无法继续进行操作。因为等到异步任务asyncTask执行完以后,还要进行从working数组中删除以及push还未执行的任务等操作。

再一次Promise封装的主要目的就是,可以让asyncTask执行完以后,将后续操作继续完成,再进行任务的轮询。

所以add方法中的asyncTask.resolve = resolve就很重要,这就保证了等到asyncTask自己的异步任务完成以后,再进行外层Promise的resolve。这便做到了asyncTask完成后,再做任务的更替。

感觉这道题的核心思想就是通过Promise的嵌套来控制主Promise的执行。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值