async / await:分批解析Promise.all()

时间:2018-06-02 08:05:10

标签: javascript async-await xmlhttprequest es6-promise

tl; dr需要一些Promises的帮助。

这里有一个小刮刀功能:

function request(method, url) {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest();
        xhr.open(method, url);
        xhr.onload = resolve;
        xhr.onerror = reject;
        xhr.send();
    });
}

我还有一个相当大的我要解决的个人资料列表:

const profiles = ['http://www.somesite.com/profile/1',
'http://www.somesite.com/profile/2'] // 100+ more

我如何分批处理它们,比如一次5个?

到目前为止,这是我的思考过程:

  1. 使用_.chunk()
  2. 拆分为N个块
  3. 等待Promise.all()解决所述chunk
  4. 这是我到目前为止所拥有的:

    async function processProfileBatch(batchOfUrls) {
        let promises = [];
    
        // Populate promises
        for (let i = 0; i < batchOfUrls.length; i++) {
            let url = batchOfUrls[i]
            promises.push(request('GET', url))
        }
    
        // Wait for .all to resolve
        return await Promise.all(promises)
    }
    const profileBatches = _.chunk(profileLinks, 3)
    for (let i = 0; i < profileBatches.length; i++) {
            let processedBatch = await processProfileBatch(profileBatches[i])
            console.log(new Date(), 'processedBatch', processedBatch);
        }
    

    不幸的是,这只会返回ProgressEvent s;在检查时,.responseText设置为“”,其中包含的xhr即使readyState为4:

    enter image description here

1 个答案:

答案 0 :(得分:0)

分块的问题在于你有x个活动请求,然后等待所有这些请求完成以启动下一个x请求数量。

使用throttle,您可以不断激活x个请求,直到完成所有操作。

//lib comes from: https://github.com/amsterdamharu/lib/blob/master/src/index.js
const lib = require("lib");

function processProfileBatch(batchOfUrls){
  const max10 = lib.throttle(10)
  return Promise.all(
    batchOfUrls.map(
      url=>
        max10(url=>request('GET', url))(url)
    )
  )
};

如果你宁愿限制每个时期的连接(比如说每秒2次)而不是限制活动连接,你可以使用throttlePeriod:

twoPerSecond = lib.throttlePeriod(2,1000);
... other code
twoPerSecond(url=>request('GET', url))(url)

您可能还希望在拒绝时丢弃所有已解决的请求。对被拒绝的请求使用特殊的解析值,您可以将被拒绝的请求与已解决的请求分开:

//lib comes from: https://github.com/amsterdamharu/lib/blob/master/src/index.js
const lib = require("lib");

function processProfileBatch(batchOfUrls){
  const max10 = lib.throttle(10)
  return Promise.all(
    batchOfUrls.map(
      url=>
        max10(url=>request('GET', url))(url)
        .catch(err=>new lib.Fail([err,url]))
    )
  )
};

processProfileBatch(urls)
.then(//this does not reject because rejects are caught and return Fail object
  result=>{
    const successes = results.filter(lib.isNotFail);
    const failed = results.filter(lib.isFail);
  }
)