有一个Promise数组,只有N同时运行

时间:2018-02-09 17:16:24

标签: javascript node.js asynchronous

假设我有60项任务,每项任务至少需要30分钟。现在我想一次只运行5个,所以当这5个中的1个完成时,另一个任务会被执行直到所有任务完成。

最干净的方法是什么?这个模式有名字吗?

2 个答案:

答案 0 :(得分:3)

我建议使用bluebird Promise.map方法,在val map = dataSnapshot.getValue(Map::class.java) as Map<String, String> 的情况下,您可以将其配置为使用并发方法。

答案 1 :(得分:0)

一种解决方案是编写一个帮助程序类来为您执行此操作。我必须自己多次使用这个模式,所以我有这个实用程序类来管理一组promises并允许一次运行不超过指定的限制:

class PromiseLimitQueue {

  constructor(limit) {
    if (Math.floor(limit) <= 0) throw new Error("Limit must be a positive integer.");
    
    this._limit = Math.floor(limit);
    this._head = [];
    this._queue = [];
  }

  // The promFunc must be a function that returns a promise, not a promise itself.
  // Method returns a new promise that resolves when the promise that promFunc
  // returns has run and resolved.
  enqueue(promFunc) {
    return new Promise((resolve, reject) => {
      const newFunc = () => promFunc().then(resolve).catch(reject);
      this._queue.push(newFunc);

      if (this._head.length < this._limit) this._pullNext();
    });
  }

  _pullNext() {
    const next = this._queue.shift();
    if (!next) return;

    const prom = next();
    const onDone = () => {
      const index = this._head.indexOf(prom);
      if (index !== -1) this._head.splice(index, 1);
      this._pullNext();
    }

    prom.then(onDone, onDone);
    this._head.push(prom);
  }
}

// Usage Example:

// Helper function returns a promise that resolves after 'num' milliseconds.
function timer(num) {
  return new Promise(resolve => {
    setTimeout(resolve, num)
  })
}

// Create a new limit queue, give desired limit (in this case, 5);
const limitQueue = new PromiseLimitQueue(5);

// Queue up 20 1-second timers, observe that only 5 ever run at once:
for (let i = 0; i < 20; i++) {
  limitQueue.enqueue(() => timer(1000)).then(() => console.log(`Timer ${i} Resolved.`))
}