首页 > 解决方案 > 使用 Promise 的 JavaScript 调度器实现

问题描述

我正在解决这个有趣的 javascript 问题(面试问题),但我一直在思考如何使用 Promise 来实现它。

问题:

用 JavaScript 编写一个调度程序,接受最大并发任务数作为参数并调度任务(每个任务可能需要任意时间才能完成)。

请注意,在继续执行其他任务之前,我们一次只需要执行“n”(并发)任务。

这是我的实现:

var exampleTaskA = function () {
    setTimeout(function () {
        console.log('Task A Done');
    }, 1000);
};

function TaskRunner(concurrency) {
    this.limit = concurrency;
    this.store = [];
    this.len = this.store.length;
}

TaskRunner.prototype.push = function (task) {
    this.store.push(task);
    function getWorker(store, limit) {
        if(!store.length) return;

        if(store.length <= limit) {
            const cur = store.shift();
            if(cur) cur();
            getWorker(store, limit);
        }
    }

    getWorker(this.store, this.limit);
}

var task = new TaskRunner(2);
console.log(task.push(exampleTaskA));
console.log(task.push(exampleTaskA));
console.log(task.push(exampleTaskA)); 
console.log(task.push(exampleTaskA));
console.log(task.push(exampleTaskA));
console.log(task.push(exampleTaskA));
console.log(task.push(exampleTaskA));

我如何使用 promises / async await 来实现它?在推动之前,我应该把所有东西都包装在一个承诺上吗?

有人能解惑吗?

标签: javascriptasynchronous

解决方案


因此,如果您可以从您的任务中返回一个承诺,您可以绑定到该承诺then(),以在任务完成以及何时开始另一个任务时提醒您。

这是一个与您的示例类似的示例,但有一些更改:我们不关心队列的长度——您只想知道有多少活动作业存在。因此,您可以在开始作业时递增active,在作业完成时递减。

有很多方法,我肯定会这样做,但这里是一个想法的大纲:

const exampleTaskA = (name) => new Promise(resolve => setTimeout(function() {
  console.log(`Task ${name} Done`);
  resolve()
}, Math.floor(Math.random() * 2000)))

function TaskRunner(concurrency) {
  this.limit = concurrency;
  this.store = [];
  this.active = 0;
}

TaskRunner.prototype.next = function() {
  if (this.store.length) this.runTask(...this.store.shift())
}

TaskRunner.prototype.runTask = function(task, name) {
  this.active++
  console.log(`Scheduling task ${name} current active: ${this.active}`)
  task(name).then(() => {
    this.active--
    console.log(`Task ${name} returned, current active: ${this.active}`)
    this.next()
  })
}
TaskRunner.prototype.push = function(task, name) {
  if (this.active < this.limit) this.runTask(task, name)
  else {
    console.log(`queuing task ${name}`)
    this.store.push([task, name])
  }
}

var task = new TaskRunner(2);
task.push(exampleTaskA, 1)
task.push(exampleTaskA, 2)
task.push(exampleTaskA, 3)
task.push(exampleTaskA, 4)
task.push(exampleTaskA, 5)
task.push(exampleTaskA, 6)
task.push(exampleTaskA, 7)


推荐阅读