使用JS promise或generator并行执行最多N个任务

时间:2017-04-02 15:29:37

标签: javascript ecmascript-6 generator es6-promise

我想实现一个JS类,它使用JS promises或generator并行执行最多N个任务。像

这样的东西
class Executor {
    constructor(numberOfMaxTasks) {
    ...
    }

    next(task) {
    ...
    }

    done(onDone) {
    ...
    }
}

....
const executor = new Executor(2);
executor.next(task1).next(task2).next(task3).done(onDone);
任务1和任务2应该并行执行,而task3应该等到上一个任务结束。当所有任务完成onDone时,执行回调。

我试图用promises实现它,但我失败了。我是发电机的新手,目前不知道他们是否可以在这里提供帮助。这主要是出于学习目的,这就是为什么我不想使用任何第三方库,只是原生JS。任何提示都会很棒,提前谢谢!

2 个答案:

答案 0 :(得分:0)

最近我不得不为你想要实现的面试解决一个测验,但是基于 Node.js 。   关键是使用类属性控制正在执行的任务量(在我的示例中为 let tasks = []; let tasksDone = []; const LIMIT = 10; class Executor { constructor () { this.running = 0; for (let i = 0; i < 1000; i++) { tasks[i] = { id: 'job_' + (i+1), time: ((i % 4) + 1) * 25 }; } } checkConcurrency () { if( this.running > LIMIT ){ throw new Error('Maximum number of tasks ['+LIMIT+'] reached'); } } execute (task) { return new Promise((resolve, reject)=>{ this.running ++; this.checkConcurrency(); setTimeout(()=>{ this.checkConcurrency(); this.running --; resolve({ ...task, finished: Date.now() }); }, task.time); }) } run () { this.startTime = Date.now(); this.executeTasks(tasks.slice(0)); } executeTasks(tasks) { while (this.running < LIMIT && tasks.length > 0) { let task = tasks.shift(); this.execute(task).then( result => { tasksDone.push(result); if (tasks.length > 0) { this.executeTasks(tasks); } }); } } } )。因此,对于一系列任务,您可以通过while循环运行它们并检查每个循环,如果您有任何可用的插槽(由this.running和LIMIT控制),然后运行promise。   此代码可能对您有所帮助。

{{1}}

答案 1 :(得分:0)

我认为您最好使用bluebird promise library

例如,bluebird provides map function可以做你想做的事情:

  • 在第一个参数中,您可以指定任务执行所需的数据数组
  • 在第二个参数中,您可以指定mapper函数,它可以实际运行您的任务并返回promise
  • 在第三个参数中,您可以指定&#34;当时大多数N个任务&#34;使用{ concurrency: N }对象。

请注意,对于bluebird.map函数,执行顺序并不保证。唯一可以保证bluebird.map的结果将以相同顺序的结果数组实现。

使用该函数,您可以在不使用Executor类的情况下重写代码(示例适用于node.js):

const Promise = require('bluebird')
const os = require('os')
const task1Data = 1000
const task2Data = 5000
const task3Data = 3000

const tasksData = [ task1Data, task2Data, task3Data ]
function taskExecutorMapper(taskData) {
  // here is place for your code that actually runs
  // asynchronous operation based on taskData and returns promise
  // I'll use setTimeout here for emulate such operation
  return new Promise(function(resolve) {
    setTimeout(resolve, taskData)
  }
}
const tasksPromise = Promise.map(
  tasksData,
  taskExecutionMapper,
  { concurrency: os.cpus().length })
  .then(onDone)

希望这有帮助!