Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for request to finish Node.js

I am currently having an issue with figuring out how to wait for the request to finish before returning any data. I do not believe I can do this with a Callback and I have not been able to figure out a good way of using the EventEmitter to do it. The reason I cannot use a callback is because my flow currently works like this.

Request comes into server > Generate XML > Contact remote API for details to finish generating XML > Finish Generating XML > Return request to client

The code I currently have looks very similar to the code included below.

Web Server:

var xml = require('./XMLGenerator');
response.writeHead(200, {'Content-Type': 'text/xml'});
response.write(xml.generateXML());
response.end();

XML Generator:

function generateXML(){
// Code to generate XML
var API = require('./API');
var response = API.getItems("5");
for(var i = 1; i <= response.length; i++)
{
  // more code to generate further XML using the API response
}

// Finish generating and return the XML
}

API Grabber:

function getItems(sort_by, amount) {
var request = require("request")

var url = "https://url.com/api/get_items.json?amount=" + amount;
request({
    url: url,
    json: true
}, function (error, response, body) {
    console.log('we got here!');
   if (!error && response.statusCode === 200) {
        var items = body.data.items;
        console.log(items);

        return items;
    } else {
        console.log("Error connecting to the API: " + url);
        return;
    }
})
}

When running the code and testing directly it returns "undefined" meaning that the request has not been made yet. I just need to know a way to make the XML generator wait for the request to finish before continuing on with the generation. (there may be minor errors in the psudeo code I typed up as it is not an exact copy paste from the source, it does however work in this flow)

Am I just using bad practices, or is this the correct way that I should be attempting this?

EDIT: The problem is not loading the module/API file, that loads perfectly fine. The problem is that the request takes about 2 seconds to complete, and that node moves on before the request completes.

like image 376
OstlerDev Avatar asked May 22 '15 06:05

OstlerDev


People also ask

How do I make node JS wait?

One way to delay execution of a function in NodeJS is to use the seTimeout() function. Just put the code you want to delay in the callback. For example, below is how you can wait 1 second before executing some code.

How do I wait for API response in node JS?

I would use async/await. If you run your whole main program in an async function that you call immediately, you can put await before any function that returns a Promise . setTimeout(function () { GetReportEmail. GetReportOnEmail( 'userID', 'ReportName', ).

How do you wait for a callback to finish?

JavaScript provides a setTimeout() method which can work with the callback function and the await keyword to wait for a function to finish. The objective of employing these methods is to execute a piece of code after waiting for a specific time.

How do you force a program to wait until an HTTP request is finished in JavaScript?

There is a 3rd parameter to XmlHttpRequest 's open() , which aims to indicate that you want the request to by asynchronous (and so handle the response through an onreadystatechange handler). So if you want it to be synchronous (i.e. wait for the answer), just specify false for this 3rd argument.


2 Answers

You need to use callbacks. Change your API grabber to this:

function getItems(amount, callback) {
// some code... 
request({
  url: url,
  json: true
}, function (error, response, body) {
   // some code...
   if (!error && response.statusCode === 200) {
      // some code    
      callback(items); <-- pass items to the callback to "return" it
   }
})
}

Then change the xml generator to also accept callbacks:

function generateXML(callback){
// Code to generate XML
var API = require('./API');
API.getItems("5",function(response){
  for(var i = 1; i <= response.length; i++)
  {
    // more code to generate further XML using the API response
  }

  // Finish generating and return the XML
  callback(xml_result); // <-- again, "return" the result via callback
});
}

Then in your server code do:

var xml = require('./XMLGenerator');
response.writeHead(200, {'Content-Type': 'text/xml'});
xml.generateXML(function(xmlstring){
    response.write(xmlstring);
    response.end();
});
like image 137
slebetman Avatar answered Sep 27 '22 21:09

slebetman


Do these changes since request is async, use callbacks.

API.getItems("5", function(rs){
      var response = rs;
      for(var i = 1; i <= response.length; i++)
      {
      // more code to generate further XML using the API response
      }

      // Finish generating and return the XML
    }

});


...
function getItems(sort_by, amount, callback) {...

...
callback(items); //Instead of return items;

...

You cannot return from an async call, which is request module in your case. In such cases you can either use promises or callbacks. This is a solution with callback.

The actual problem of it returning undefined is it doesnot wait for var response = API.getItems("5"); to execute completely and executes the next line and hence you get response as undefined. I hope you get the point.\

Also I hope

response.writeHead(200, {'Content-Type': 'text/xml'});
response.write(xml.generateXML());
response.end();

is somewhere inside some callback of an API or http.createServer.

like image 27
Zee Avatar answered Sep 27 '22 23:09

Zee