I’m trying to understand why I’m seeing the following:
I fire off several async requests inside a for loop and then simply print out the responses. Here’s a very simplified version of what I’m doing:
function getStuff(){
var singers = ['marley','matthews','johnson','buffett'];
for(lastname in singers){
var lastName = singers[lastname];
log("Making request for "+ singers[lastname]);
makeAsyncRequest(singers[lastname], function(response){
//this is the callback when the async request returns
log("RESPONSE - "+lastName+": "+response);
});
}
}
If I run the code with syncronously (async: false), I get the following results as expected every time:
Making request for marley
Making request for matthews
Making request for johnson
Making request for buffett
RESPONSE - marley: bob
RESPONSE - johnson: jack
RESPONSE - matthews: dave
RESPONSE - buffett: jimmy
When I run asyncronously, I see results like the following. I understand that the responses might come back out of order. But what I don’t understand is when they come back out of order, why do I see duplicate values? For example, I might see:
Making request for marley
Making request for matthews
Making request for johnson
Making request for buffett
RESPONSE - marley: bob
RESPONSE - johnson: dave
RESPONSE - matthews: dave
RESPONSE - buffett: jimmy
Notice ‘dave’ seems to be returned twice? I would understand if the values ‘jack’ and ‘dave’ were switched, like so:
Making request for marley
Making request for matthews
Making request for johnson
Making request for buffett
RESPONSE - marley: bob
RESPONSE - johnson: dave
RESPONSE - matthews: jack
RESPONSE - buffett: jimmy
But I don’t understand why the “response” param in the callback appears to be getting set to the same value twice? Am I overlooking something basic here?
Thanks for any help!
A loop does not have its own scope. The problem is, that there is only one
lastNamevariable and when the async request returns its content will not always be the content you assigned to it in the iteration.You should read and understand how the scope in JavaScript works.
A solution could be an additional closure in your loop: