How to make it so that I can execute, say, 10 promises at a time in javascript to prevent speed limit for api calls?

I have 1000 entries that should hit the API endpoint, which is speed limited. I want to make sure that there are only 5 calls to the URL at any given time, so I do not make 1000 requests at the same time. How can i do this? I have the following:

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); }) } 
+1
source share
2 answers

To limit the number of simultaneous requests that are in flight at a time, I would recommend using Bluebird Promise.map() , which offers the concurrency option. He will do all of the following for you:

  • Iterate your array
  • Limit the number of simultaneous requests to what you set for the concurrency parameter so that
  • Collect all the results in order in an array of final results

Here's how you use it:

 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 }); 

Note. The speed limit is usually independent of the number of simultaneous requests. Limiting the number of simultaneous requests will lead to a greater likelihood that you will remain under the rate limit, but do not guarantee it. There are special speed limit modules that can directly control the speed limit.


You can add a delay to each request using Bluebird .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 }); 

The classic algorithm for dealing with some types of speed limits is called the leaky bucket algorithm .


If your limit is 50 requests / sec, you can just make sure your concurrency number multiplies the delay time by more than 50 / sec.

0
source

Use a waterfall drawing without a library and use the race condition to resolve at each iteration with a decrease. And you can limit the number of calls by specifying the length of the array in 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); }); } 
0
source

Source: https://habr.com/ru/post/1272472/


All Articles