0

I have a loop, which iterates over array and in every iteration I have to do a http request, like this:

var httpsRequest = require('request')
var getData = function(id) {
        var result;
    httpsRequest({
            url: 'https://link/'+id,
        }, (error, resp, body) => {
            if(resp.statusCode == 200) {
                result = JSON.parse(body);

            }
        });  
      //here I would like to wait for a result  
}

var data = [];
for(row in rows) {
    data.push(getData(row.ID))
}
resp.send(JSON.stringify(data)) //I send data back to the client

I cannot do the rest of the for loop in callback, I have to wait for a result which will be returned from a function getData and move to the next iteration. How to handle this?

PS I know I could use callback function but what if after the last iteration program will send the response (last line above) before the last getData execution finish?

Regards

2 Answers 2

2

As stated in the answer by Johannes, the use of promises is a good idea. Since you're using request I'd like to propose an alternative method by using request-promise which is a promisified version of 'request' using bluebird.

The requests will in this case return a promise, and by using .map() you can create an array of promises that you can await using Promise.all(). When all promises are resolved, the response can be sent! This also differs from the use of .reduce(), which only will start to execute the next request as soon as the previous one is done. By using an array of promises, you can start all the requests at the same time.

var httpsRequest = require('request-promise')
var getData = function(id) {
    return httpsRequest({
        url: 'https://link/' + id,
    }, (error, resp, body) => {
        if(resp.statusCode == 200) {
            return JSON.parse(body);
        } else {
            //Throw error, this will be caught in the .catch() 
            throw error;
        }
    });  
}

var promises = rows.map(function(row){
    return getData(row.ID)
});

Promise.all(promises)
    .then(function(results){
        //All requests are done!
        //The variable results will be an array of all the results in the same order as they were requested
        resp.send(JSON.stringify(results));
    })
    .catch(function(error){
        //Handle the error thrown in the 'getData' function
    });
Sign up to request clarification or add additional context in comments.

Comments

1

If you need to wait for each iteration to be done before starting another one, you can use Promises and reduce. If you only want to wait for all requests to be finished it's better to use map + Promise.all as explained in Daniel Bs answer.

// i asume rows is an array as you wrote you iterate over one.
const results = [];
rows.reduce((previous, row) => {
  return previous.then(() => getData(row.ID).then(result => results.push(result)) // do whatever you want with the result
  );
}, Promise.resolve())
.then(() => resp.send(JSON.stringify(results)));

const getData = (id) =>  {
  return new Promise((resolve, reject)=> {
    httpsRequest({
      url: 'https://link/'+id,
    }, (error, resp, body) => {
      if(error) return reject(error);
      if(resp.statusCode == 200) {
        return resolve(JSON.parse(body));
      }
      return resolve(); // if you want to pass non 200 through. You may want to do sth different here
    });
  });
};

6 Comments

What is "reduce" stand for?
Even though this works, a drawback of reduce() is that they will run in sequence which isn't necessary.
@DanielB i know, but he specificly said that he wants to wait: > I have to wait for a result which will be returned from a function getData and move to the next iteration
Ah, that's right, didn't spot that! Though thats only a comment, so I'm not sure it's really what you think it means. Good catch though, perhaps you should update your answer to explain why you use .reduce() to make that more clear.
@DanielB thanks for pointing that out. Have updated my answer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.