Reputation: 531
I've written a program that makes an HTTP GET request for three distinct URLs. The program is supposed to output the message body in the order the URLs are provided, however it's not doing so even though I'm making callbacks in exactly that order.
The final program is supposed to require the user to input the URLs via command line, however I've simply made variable assignments for ease of testing.
I realize this code could be more object-oriented - however I'm new to JavaScript and it's not my focus to learn how at the moment
var http = require('http')
// var url_1 = process.argv[2]
// var url_2 = process.argv[3]
// var url_3 = process.argv[4]
var url_1 = 'http://youvegotmail.warnerbros.com/cmp/0frameset.html'
var url_2 = 'http://www.3riversstadium.com/index2.html'
var url_3 = 'http://toastytech.com/evil/'
var output_1 = ''
var output_2 = ''
var output_3 = ''
function getHttp_1 (callback) {
http.get(url_1, function getResponse (response1) {
response1.setEncoding('utf8')
response1.on('data', function (data) {
output_1 = output_1 + data
})
response1.on('end', function processData() {
console.log("Printing Result 1:")
callback(output_1)
})
})
}
function getHttp_2 (callback) {
http.get(url_2, function getResponse (response2) {
response2.setEncoding('utf8')
response2.on('data', function (data) {
output_2 = output_2 + data
})
response2.on('end', function processData() {
console.log("Printing Result 2:")
callback(output_2)
})
})
}
function getHttp_3 (callback) {
http.get(url_3, function getResponse (response3) {
response3.setEncoding('utf8')
response3.on('data', function (data) {
output_3 = output_3 + data
})
response3.on('end', function processData() {
console.log("Printing Result 3:")
callback(output_3)
})
})
}
function printResults(output) {
console.log("Result")
// console.log(output)
}
getHttp_1(printResults)
getHttp_2(printResults)
getHttp_3(printResults)
EDIT:
Results I'm generally getting:
Printing Result 3:
Result
Printing Result 2:
Result
Printing Result 1:
Result
Results I'm expecting:
Printing Result 1:
Result
Printing Result 2:
Result
Printing Result 3:
Result
Upvotes: 1
Views: 248
Reputation: 17430
In contrast to the sequential callback approach proposed by some answers, using Promises will make this both more efficient (the requests will be made in parallel) and simpler:
var http = require('http'),
urls = [
'http://youvegotmail.warnerbros.com/cmp/0frameset.html',
'http://www.3riversstadium.com/index2.html',
'http://toastytech.com/evil/'
];
Promise.all(urls.map(getUrl))
.then(function (results) {
results.forEach(function (output, i) {
console.log("Result #" + (i + 1) +
" with length: " + output.length);
});
});
function getUrl(url, i) {
return new Promise(function (resolve, reject) {
http.get(url, function getResponse(resp) {
var output = '';
resp.setEncoding('utf8');
resp.on('data', function (data) {
output += data;
});
resp.on('end', function processData() {
console.log("Resolving Result " + (i + 1) + ":");
resolve(output);
});
})
});
}
Upvotes: 3
Reputation: 78900
The async module can really help for controlling how async tasks are executed. For example, if you want your requests to happen one after the other:
async.series([
function (next) { makeRequest(url_1, next); },
function (next) { makeRequest(url_2, next); },
function (next) { makeRequest(url_3, next); },
], function (err, result) {
// All done
});
// Or you can get fancy
//async.series([
// makeRequest.bind(null, url_1),
// makeRequest.bind(null, url_2),
// makeRequest.bind(null, url_3),
//]);
function makeRequest(url, callback) {
http.get(url, function getResponse (res) {
var output = '';
res.setEncoding('utf8')
res.on('data', function (data) {
output += data
})
response1.on('end', function processData() {
callback(output)
})
})
}
If you don't care what order they occur in but want to output them in order:
async.parallel([
function (next) { makeRequest(url_1, next); },
function (next) { makeRequest(url_2, next); },
function (next) { makeRequest(url_3, next); },
], function (err, results) {
if (err) {
return void console.error('Got an error:', err.stack);
}
console.log(results); // Will output array of every result in order
});
If the requests are dependent on each other, async.auto
is useful to tie the result of one request to the request of another.
Upvotes: 2
Reputation: 3800
JavaScript/AJAX calls are async so don't follow the order you call them. To call them in sequence/specific order, do like:
$(function () {
//setup an array of AJAX options, each object is an index that will specify information for a single AJAX request
var ajaxes = [{ url : '<url>', dataType : 'json' }, { url : '<url2>', dataType : 'utf8' }],
current = 0;
//declare your function to run AJAX requests
function do_ajax() {
//check to make sure there are more requests to make
if (current < ajaxes.length) {
//make the AJAX request with the given data from the `ajaxes` array of objects
$.ajax({
url : ajaxes[current].url,
dataType : ajaxes[current].dataType,
success : function (serverResponse) {
...
//increment the `current` counter and recursively call this function again
current++;
do_ajax();
}
});
}
}
//run the AJAX function for the first time once `document.ready` fires
do_ajax();
});
Another option could be:
function callA() {
$.ajax({
...
success: function() {
//do stuff
callB();
}
});
}
function callB() {
$.ajax({
...
success: function() {
//do stuff
callC();
}
});
}
function callC() {
$.ajax({
...
});
}
callA();
Upvotes: 0
Reputation: 1318
Welcome to the asynchronous life of node.js! As you fire off those HTTP requests, one will not wait for the request before it to finish before it fires. You are seeing this odd behavior because you are practically sending all 3 requests at once, and simply printing as you see the responses.
Edit: If you do want to see them in correct order, fire off the second HTTP request inside the callback of the first, and then the third inside the callback of the second. That guarantees you won't get the data until after each one before it finishes.
function getHttp_1 (callback) {
http.get(url_1, function getResponse (response1) {
response1.setEncoding('utf8')
response1.on('data', function (data) {
output_1 = output_1 + data
})
response1.on('end', function processData() {
console.log("Printing Result 1:")
callback(output_1)
getHttp_2(callback)
})
})
}
Upvotes: 2