手写题 - 实现一个带并发限制的异步调度器

题目

实现一个带并发限制的异步调度器 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')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')

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

核心思路:考察 Promise知识点;当任务数超过规定任务数,创建微任务进行等待。

代码实现

class Scheduler {
    constructor(max) {
        this.max = max;
        this.count = 0; // 当前执行中的异步操作
        this.queue = new Array(); // 记录当前的执行数组
    }
    
    async add(promiseCreator) {
        // count >= max 时,此时先不直接执行,将当前异步操作存储起来,当count满足时,再去执行
        // Promise.then的链式调用 new Promise((resolve) => { setTimeout(() => {}, 10000}).then xxxx
        if (this.count >= this.max) {
           /** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */
            await new Promise((resolve, reject) => {
                this.queue.push(resolve);
            });
        }
        
        /** queue某一项resolve()后会从这儿往下走  */
        this.count++;
        let res = await promiseCreator();// 执行timeout(time)
        this.count--; // 执行完1轮才往下走到这儿
        
        if (this.queue.length) {
            this.queue.shift()();//删除queue数组第一项并执行resolve()
        }
        
        return res;
    }
}
    
const timeout = (time) => new Promise(resolve => {
  setTimeout(resolve, time)
})

const scheduler = new Scheduler(n) // 任务2=>n即为2
const addTask = (time, order) => {
  scheduler.add(() => timeout(time)).then(() => console.log(order))
}

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

运行结果如下

手写题 - 实现一个带并发限制的异步调度器_第1张图片

通过输出结果分析代码执行顺序

class Scheduler {
  constructor(max) {
    this.max = max
    this.count = 0 
    this.queue = new Array() 
  }

  async add(promiseCreator) {
    if (this.count >= this.max) {
      await new Promise((resolve, reject) => {
        this.queue.push(resolve)
      })
    }
    this.count++
    const res = await promiseCreator()
    this.count--

    if (this.queue.length) {
      this.queue.shift()()
    }
    console.log('res: ', res)

    return res
  }
}
const timeout = (time) => new Promise(resolve => {
  console.log('100')
  setTimeout(resolve, time)
})

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

addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
打印结果:
100
100

res: undefined
100
2

res: undefined
100
3

res: undefined
1

res: undefined
4

输出结果分析

  • Part 1:
    (1)addTask1000、addTask500:
    走两次到这儿
    this.count++
    const res = await promiseCreator(); 都输出’100’,先打印2个'100'
    (2)addTask300、addTask400:
    /** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */
    await new Promise((resolve, reject) => {
    this.queue.push(resolve);
    });
  • Part 2:
    (3)500ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (4)∵this.queue.shift()()即resolve()是同步代码,
    addTask300走到这儿
    this.count++
    const res = await promiseCreator();
    ∴先打印下一个'100'再return res打印'2'
  • Part 3:
    (5)接下来同理,300ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (6)∵this.queue.shift()()即resolve()是同步代码,
    addTask400走到这儿
    this.count++
    const res = await promiseCreator();
    ∴先打印下一个'100'再return res打印'3'
  • Part 4:
    (7)1000ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (8)没有下一个’100’了,return res打印'1'
  • Part 5:
    (9)400ms的timeout执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (10)没有下一个’100’了,return res打印'4'

在这里插入图片描述

你可能感兴趣的:(前端,js,javascript,前端,vue.js)