1

I have gone through questions about returning data from a node JS request call. A common mistake is assuming statements are executed line by line or synchronously, which is not the case here. A question of this type: How to get data out of a Node.js http get request.

My question is a bit different. I have written a function getNumber() which returns the number of results for given query. I am wondering how I return a value retrieved by the callback function? So for instance:

function getNumResults() { 

Request(url, function(response) { 

    var responseJSON = JSON.parse(body); 
    return(responseJSON.results.count); 

   }); 

}

function Request(URL, callback) {

request(URL,  function(error, response, body) { 

    console.log('URL: ', URL); 
    console.log('error: ', error); 
    console.log('statusCode: ', response && response.statusCode); 
    console.log('body: ', body); 
    callback(body); 
}); 

}

What if I want getNumResults() to return responseJSON.results.count? How could I do this?

Diana Vazquez Romo
  • 152
  • 1
  • 1
  • 11

1 Answers1

4

What if I want getNumResults() to return responseJSON.results.count? How could I do this?

You can't directly return an async value from getNumResults(). You just can't. The function returns long before the value is even available. It's a matter of timing. That's how async responses work. They finish some indeterminate time in the future, but they are non-blocking so the rest of your Javascript continues to run and thus the function returns before the result is even available.

The ONLY way to get the result out is with a callback of some kind. That applies to both your Request() function and to our getNumResults() function. Once a result is asynchronous, nobody in the calling chain can escape that. Async is infectious and you can never go from async back to synchronous. So, if your getNumResults() wants to get the value back to its caller, it will either have to accept a callback itself and call that callback when it gets the value or it will have to return a promise that is resolved with the value.

Here's how you could do this using promises (which are the future of async development in Javascript):

// load a version of the request library that returns promise instead of
// taking plain callbacks
const rp = require('request-promise');

function getNumResults(url) {
    // returns a promise
    return rp(url).then(body => {
        // make the count be the resolved value of the promise
        let responseJSON = JSON.parse(body);
        return responseJSON.results.count;
    });
}

Then, you would use getNumResults() like this"

getNumResults(someURL).then(count => {
    // use the count result in here
    console.log(`Got count = ${count}`);
}).catch(err => {
    console.log('Got error from getNumResults ', err);
});

FYI, I think you can also get the request() library to parse your JSON response for you automatically if you want by setting an appropriate option {json: true}.


EDIT Jan, 2020 - request() module in maintenance mode

FYI, the request module and its derivatives like request-promise are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got() myself and it's built from the beginning to use promises and is simple to use.

jfriend00
  • 683,504
  • 96
  • 985
  • 979