等待 x 数量的承诺完成以产生新承诺的好模式是什么?

What is a good pattern for waiting until x number of promises are completed to spawn a new promise?

我一直在搜索并找到了它的一些变体,但没有找到完全满足我需要的东西。下面是我试图找出的伪代码:

var itemsUploading = 0;
const maxUploads = 10;


function uploadAll(items){
    var promises = [];
    items.forEach(function(item){

        /* Here is where I want to wait for itemsCurrentlyUploading < maxUploads */

        itemsUploading++;            
        promises.push(upload(item));            
    }
    return Promise.all(promises);

}

function upload(item){
    return new Promise(function(resolve, reject){

        /*Item upload logic here */

    })
    .then(function(response){
        itemsUploading--;
    });
}

我知道您不能阻止同步代码来等待异步,我已经尝试了几种变体。我认为 setTimeout 是我可以用来执行此操作的东西,但我不太理解必要的逻辑。任何和所有帮助将不胜感激,如果有任何其他我可以编辑它以帮助别人更好地理解问题,请告诉我,谢谢!

由于 JavaScript 在数据结构上有点稀疏,我们将不得不凑合。

let pending = new Set;
let maxPendingItems = 5; // could be whatever number

let wrapPromiseFn = f => (...args) => {
  let p = f(...args);
  pending.add(p);
  p
    .then(() => pending.remove(p))
    .catch(e => {
      console.warn(e);
      pending.remove(p);
    });

  return p;
};

let performAsyncIO = wrapPromiseFn(someAJAXFn);

现在你可以有一个循环来监控集合的大小,看看它是否已经清除到足以添加新项目的程度。只需确保像上面那样用 wrapPromiseFn 修饰返回 Promise 的函数。

let flag = true;
while (flag) {
  if (pending.size <= maxPendingItems) {
    // promise will automatically queue until resolved
    performAsyncIO().then(responseHandler);
  }
}

我想您可能会发现 Bluebird 库中的 Promise.map 之类的东西很有用。 concurrency 参数允许您设置 "pending" 承诺的最大数量。

简单的解决方案,但我想不像 Bluebird 那样经得起考验,可作为 standalone NPM package