使用promise实现JavaScript Scheduler

时间:2018-08-14 21:51:04

标签: javascript asynchronous

我正在解决这个有趣的javascript问题(面试问题),我陷入了如何使用promises实现这一问题的问题。

问题:

  

在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等待来实现呢?在执行之前,我应该将所有内容都包裹在一个诺言中吗?

有人可以开导吗?

2 个答案:

答案 0 :(得分:3)

因此,如果您可以从任务中返回承诺,则可以绑定到承诺的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)

答案 1 :(得分:-1)

window.addEventListener(“ load”,function(){ //这是没有承诺的

function Task(name) {
    this.isDone = false;
    this.name = name;
}

Task.prototype.run = function() {
    setTimeout(()=>{
        this.isDone = true;
    }, 3000);
}

function TaskScheduler(limit) {
    this.limit = limit;
    this.active = 0;
    this.pendingTasks = [];
    this.runningTasks = [];
}

TaskScheduler.prototype.runTask = function(task) {
    this.active++;
    task.run();
}

TaskScheduler.prototype.init = function() {
    var interval = setInterval(() => {
        // check and clean running tasks
        this.runningTasks = this.runningTasks.filter((task) => {
            if (task.isDone) {
                this.active--;
            }
            return !task.isDone;
        });

        while(this.pendingTasks.length) {
            if (this.active < this.limit) {
                var task = this.pendingTasks.pop();
                this.runTask(task);
                this.runningTasks.push(task);
            } else {
                break;
            }
        }

        if (!this.pendingTasks.length) {
            clearInterval(interval);
        }
    }, 0);
}

TaskScheduler.prototype.push = function(task) {
    this.pendingTasks.push(task);
}

var taskSecheduler = new TaskScheduler(2);
taskSecheduler.push(new Task(1));
taskSecheduler.push(new Task(2));
taskSecheduler.push(new Task(3));
taskSecheduler.push(new Task(4));
taskSecheduler.push(new Task(5));
taskSecheduler.push(new Task(6));
taskSecheduler.init();

});