Reputation: 51
I know many topics on this subject already exist (eg How do I return the response from an asynchronous call?) but currently I'm in a state of information overload and I can't seem to get it done. Many topics say to use synchronous requests but since this is not desirable (and by the way not supported anymore by my browser) so I must avoid this.
Problem:
I have a list. I want to pass each item to an ajax request to collect some additional information. The result should be a new list with the additional data.
var list=['a','b','c','d'];
var newlist=[];
for(element in list)
{
var item=list[element];
$.ajax({
url: "process.php",
type:"get",
data:{content:item}
}).success(function(response)
{ newlist.push([item,response]);}
}};
}
I figured now I should have a list like
newlist=[ ['a','response'],['b','response'],['c','response'],['d','response'] ];
(with 'response' being the actual response of course). However, this is not the case. When I place an alert in the success function to display the item it shows 'd' four times.
What am I doing wrong?
Upvotes: 2
Views: 1450
Reputation: 6932
Actually, you're having a closure problem (there are hundreds of posts in SO that address it). You can check this post in order to get a full explanation (or find a good article on the internet).
In essence, the problem stems from the fact that the for
is synchronous, whilst the ajax calls are asynchronous. This means that your for loop will finish before any ajax call will do. The callbacks of the Ajax wrap over item
, and item
will be d
for all of them (therefore the four d
).
A quick fix would be to use a forEach instead. To prove it, your problem can be simulated using another aynchronous function instead of your ajax call:
var list = ['a', 'b', 'c', 'd'];
var newlist = [];
// Closure problem
for (element in list) {
var item = list[element];
setTimeout(() => console.log(item), 0);
}
// No closure problem
list.forEach((item) => setTimeout(() => console.log(item), 0));
So, applying this to your code, I think your problem could be solved as follows:
var list = ['a', 'b', 'c', 'd'];
var newlist = [];
list.forEach(function(item) {
$.ajax({
url: "process.php",
type: "get",
data: {
content: item
}
}).success(function(response) {
newlist.push([item, response]);
}
}
});
Hope it helps.
Upvotes: 0
Reputation: 1427
try with async: false
by default $.ajax method is async: true with async: true any variable outside the callback function cannot be change.
var list=['a','b','c','d'];
var newlist=[];
for(element in list)
{
var item=list[element];
$.ajax({
url: "process.php",
type:"get",
data:{content:item},
async: false
})
.success(function(response){
newlist.push([item,response]);
});
}
console.log(newlist);
Upvotes: -1
Reputation: 6141
Wrap the Ajax call in function and have it call itself in recursion in success.
In success simply push the results from server in the newList array.
If the result from the server is empty, then continue with the execution.
Upvotes: 1