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.
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.
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', ).
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.
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.
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();
});
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With