Reputation: 1207
I'm using Express.js as middleware for my application. My frontend application calls an express route every couple of seconds with different parameters. The route then makes calls for each parameter to an 3rd party api. Inside each of these calls data is added to an array. After the for loop i send the the array back to the frontend.
I declare the array inside the route but the returned result is empty. When I declare the array outside the route it is working, but this is not optimal when multiple requests are made at the same time.
server.js
app.get('/prices', function(req, res){
//array for holding all feeds
var feedData = [];
//Url params
var target = req.param('target');
//Convert the params to an array
var targetArray = target.split(',');
//Loop through targets and do request
for (var i = 0; i < targetArray.length; i++) {
//API endpoint
var url = xxx;
request(url, function (error, response, body) {
//Parse the XML body to javascript objects or json
parseString(body, function (err, result) {
//Store result in js object
var resultObject = result;
var arrayObject = resultObject.quotes.quote;
feedData.push(arrayObject[0])
});
});
}
console.log(feedData);
res.send(feedData);
//Clear feedData
feedData = [];
});
So bottom line is that the array is empty. Any suggestions?
Upvotes: 1
Views: 2041
Reputation: 197
This is because javascript is asynchronous and you send data before it's ready, so you need check for last request response and return collected data.
app.get('/prices', function(req, res){
//array for holding all feeds
var feedData = [];
//Url params
var target = req.param('target');
//Convert the params to an array
var targetArray = target.split(',');
//Loop through targets and do request
for (var i = 0; i < targetArray.length; i++) {
//API endpoint
var url = xxx;
request(url, function (error, response, body) {
//Parse the XML body to javascript objects or json
parseString(body, function (err, result) {
//Store result in js object
var resultObject = result;
var arrayObject = resultObject.quotes.quote;
feedData.push(arrayObject[0]);
//If is last request return result
if(i==targetArray.length-1){
console.log(feedData);
return res.send(feedData);
}
});
});
}
});
Upvotes: 0
Reputation: 38519
You're being bitten by the async nature of node js (well, Javascript)
The call to request
is asynchronous, and accepts a callback, but you're skirting over it, so your final console.log(feedData);
etc... call is called before the callback of request
is called.
Take a look at the async module, in particular eachSeries
A non-tested example of your code, using the async library:
app.get('/prices', function(req, res) {
//Url params
var target = req.param('target');
//Convert the params to an array
var targetArray = target.split(',');
//array for holding all feeds
var feedData = [];
async.eachSeries(targetArray, function(targetArrayItem, cb) {
request(url, function(error, response, body) {
//Parse the XML body to javascript objects or json
parseString(body, function(err, result) {
//Store result in js object
var resultObject = result;
var arrayObject = resultObject.quotes.quote;
feedData.push(arrayObject[0])
//call the callback to iterate next item in targetArray
cb();
});
});
}, function(err) {
//all done
console.log(feedData);
res.send(feedData);
//Clear feedData
feedData = [];
})
});
Upvotes: 3