提问者:小点点

限制并发性并等待所有promise完成,即使有些promise被拒绝


我的问题基本上是

  • 限制并发的最佳方法是什么?
  • 等待所有承诺完成,即使有些承诺被拒绝

我知道promise.allsetleds,但是我没有找到一种好的方法来限制并发性。

到目前为止我得到的是:

使用P-limit的想法1:

const pLimit = require('p-limit');
const limit = pLimit(10);

let promises = files.map(pair => {
    var formData = {
        'file1': fs.createReadStream(pair[0]),
        'file2': fs.createReadStream(pair[1])
    };
        
    return limit(() => uploadForm(formData));
});
    
(async () => {
    const result = await Promise.allSettled(promises).then(body => {
        body.forEach(value => {
            if(value.status == "rejected")
                file.write(value.reason + '\n---\n');
        });
    });
})();

这个解决方案的问题是,我必须首先创建所有的承诺,在这样做的时候,为每个承诺打开两个文件流,这样就会达到打开文件的极限。

想法2使用p-queue:我尝试使用生成器函数在queue.on'next'事件中创建和添加新的承诺,但我无法使其正常工作,这可能不是该工作的合适工具。

想法3使用许诺池:这在一开始看起来非常有希望。其中一些支持生成器函数来为池创建承诺,但我找不到一个明确声明要像promise.allsetleds那样工作的函数。

我实现了ES6-promise-pool,却发现它会在第一次拒绝承诺后停止。


共1个答案

匿名用户

自己实现它非常简单--创建一个函数数组,当被调用时,返回承诺。然后实现一个limiter函数,该函数从该数组中获取函数并调用它们,一旦完成,再次递归调用limiter,直到数组为空:

null

const request = (file) => new Promise((res, rej) => {
  console.log('requesting', file);
  setTimeout(() => {
    if (Math.random() < 0.5) {
      console.log('resolving', file);
      res(file);
    } else {
      console.log('rejecting', file);
      rej(file);
    }
  }, 1000 + Math.random() * 1000);
});
const files = [1, 2, 3, 4, 5, 6];

const makeRequests = files.map(file => () => request(file));
const results = [];
let started = 0;
const limit = makeRequest => {
  const i = started++;
  return Promise.allSettled([makeRequest()])
    .then(result => {
      results[i] = result[0];
      if (makeRequests.length) return limit(makeRequests.shift());
    })
};
Promise.all([
  limit(makeRequests.shift()),
  limit(makeRequests.shift()),
])
  .then(() => {
    console.log(results);
  });