0

I use the node request ajax package. So, i have an loop, in every iteration it makes an request to my server.

// realItems needs the complete value of items assigned
var realItems;

var items = [];
_.forEach(JSON.parse(body), (value, key) => {
  request('myurl/' + id, (error, response, body) => {
    items = JSON.parse(body)
  });
});

How can i bundle all my requests from request package, so I can assign the value of items variable to the realItems at the end?

// edit:

I use react js, so in this case realItems is an state, and i can't trigger it in every loop iteration, because render triggers on every setState

nutzt
  • 2,773
  • 3
  • 17
  • 26
  • What is the result of `JSON.parse(body)` and why are you not using anything from it in your `request()` call? – jfriend00 Jul 16 '15 at 21:13

2 Answers2

2

There are a number of ways to approach this. Here's a brute force method that does not preserve the order of the results:

var items = [];
var cnt = 0;
_.forEach(JSON.parse(body), (value, key) => {
  ++cnt;
  request('myurl/' + value.id, (error, response, body) => {
    items.push(JSON.parse(body));
    // if all requesets are done
    if (--cnt === 0) {
        // process items here as all results are done now
    }
  });
});

Here's a version that uses Bluebird promises:

var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
Promise.promisifyAll(request);

var promises = [];
_.forEach(JSON.parse(body), (value, key) => {
    promises.push(request('myurl/' + value.id));
});
Promise.all(promises).then(function(results) {
    // all requests are done, data from all requests is in the results array
    // and are in the order that the requests were originally made
});

And, here's a little bit simpler Bluebird promises method that uses a Bluebird iterator:

var Promise = require('bluebird');
var request = Promise.promisify(require("request"));
Promise.promisifyAll(request);

Promise.map(JSON.parse(body), function(value) {
    return request('myurl/' + value.id);
}).then(function(results) {
    // all requests are done, data is in the results array
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • thank you! That with the counter might work, but what I would also like to prefer more elegant way, something like Promises. And sorry for my code, it is really simplified. So, JSON.parse(body) is from outside request (it is really only an array with 3 items, so i know how many loops i need to make). The `id` is also comes from `value` and is in my code `value.id` – nutzt Jul 16 '15 at 21:13
  • @nutzt - I added a version that uses promises. – jfriend00 Jul 16 '15 at 21:18
  • mh i become `ReferenceError: requestAsync is not defined` – nutzt Jul 16 '15 at 21:37
  • @nutzt - I corrected it. `request()` is a bit of an odd module so you have to promisify it a bit differently - my mistake. Details on that promisification issue [here](http://stackoverflow.com/questions/28308131/how-do-you-properly-promisify-request). – jfriend00 Jul 16 '15 at 21:46
1

Is it a requirement that you use the request package? I use async which is similar and comes with a parallel method which does exactly what you're asking -

https://github.com/caolan/async#parallel

example:

async.parallel([
  function(callback){
    setTimeout(function(){
        callback(null, 'one');
    }, 200);
  },
  function(callback){
    setTimeout(function(){
        callback(null, 'two');
    }, 100);
  }
],
// optional callback
function(err, results){
    // the results array will equal ['one','two'] even though
    // the second function had a shorter timeout.
});
Tom Netzband
  • 1,110
  • 1
  • 6
  • 13