Как сделать так, чтобы я мог выполнять, скажем, 10 обещаний за раз в javascript, чтобы предотвратить ограничение скорости вызовов API?

У меня есть 1000 записей, которые должны попасть в конечную точку API с ограниченной скоростью. Я хочу сделать так, чтобы в каждый момент времени на URL приходилось всего 5 вызовов, чтобы я не делал 1000 запросов одновременно. Как я могу это сделать? У меня есть следующее:

var Promise = require("bluebird");
var geocoder = Promise.promisifyAll(require('geocoder'));
var fs = require('fs');
var async = require('async');
var parse = require('csv-parse/lib/sync');
var inputFile = './myaddresses.txt'
var file = fs.readFileSync(inputFile, "utf8");

var records = parse(file, {columns: true});
var promises = [];
for(var i = 0; i < records.length; i++) {
    var placeName = records[i]['Place Name'];
            promises.push(geocoder.geocodeAsync(placeName));    
}

Promises.all(promises).then(function(result) {
  result.forEach(function(geocodeResponse) {
  console.log(geocodeResponse);
  })
}

2 ответа

Решение

Чтобы ограничить количество одновременных запросов, выполняемых одновременно, я бы рекомендовал использовать Bluebird Promise.map() который предлагает вариант параллелизма. Он сделает все следующее для вас:

  1. Итерируйте свой массив
  2. Ограничьте количество одновременных запросов тем параметром параллелизма, который вы установили на
  3. Соберите все результаты по порядку в массиве окончательных результатов.

Вот как вы бы это использовали:

const Promise = require('bluebird');

Promise.map(records, r => {
    let placeName = r['Place Name'];
    return geocoder.geocodeAsync(placeName));
}, {concurrency: 5}).then(results => {
    // all results here
}).catch(err => {
    // process error here
});

Примечание. Ограничение скорости обычно не совпадает с количеством одновременных запросов. Ограничение количества одновременных запросов повысит вероятность того, что вы останетесь без ограничения скорости, но не гарантируете это. Существуют специальные модули ограничения скорости, которые могут управлять лимитом скорости более напрямую.


Вы можете добавить задержку к каждому запросу, используя Bluebird's .delay(),

const Promise = require('bluebird');

Promise.map(records, r => {
    let placeName = r['Place Name'];
    return geocoder.geocodeAsync(placeName)).delay(500);
}, {concurrency: 5}).then(results => {
    // all results here
}).catch(err => {
    // process error here
});

Классический алгоритм для работы с некоторыми типами ограничений скорости называется алгоритмом утечки.


Если ваш лимит составляет 50 запросов / сек, то вы можете просто убедиться, что число одновременных обращений, умноженное на значение задержки, никогда не превышает 50/ сек.

Используйте шаблон водопада без библиотеки и используйте условие гонки, чтобы разрешить на каждой итерации с помощью Reduce. И вы можете ограничить количество вызовов, указав длину массива в Array.from.

var promise = Array.from({ length: 5 }).reduce(function (acc) {
  return acc.then(function (res) {
    return run().then(function (result) {
      res.push(result);
      return res;
    });
  });
}, Promise.resolve([]));


var guid = 0;
function run() {
  guid++;
  var id = guid;
  return new Promise(resolve => {
    // resolve in a random amount of time
    setTimeout(function () {
      console.log(id);
      resolve(id);
    }, (Math.random() * 1.5 | 0) * 1000);
  });
}

Другие вопросы по тегам