jQuery AJAX calls in for loop
Solution 1
The easiest way is to use a closure. Whenever you have something asynchronous in a loop, it is the same thing.
for (var i .....) {
asynchronousFunction(function() {
use(i);
}
}
In this pseudocode snippet, the inner function captures the storage location referenced by i
. The loop runs, the i
increments to its final value, and then the async callbacks start getting called, all of them looking up the exact same location (not value).
The general solution is this:
for (var i .....) {
(function (i) {
asynchronousFunction(function() {
use(i);
});
})(i);
}
i.e. wrap the whole contents of your loop in an self-executing function.
Here, the value of outer i
gets passed into the wrapping self-executing anonymous function; this unique value's location gets captured by the async callback. In this way, each async gets its own value, determined at the moment the self-executing function is invoked.
Solution 2
The links in the comment section of the question tells you what is wrong in your code... but you can have a better solution than the once explained there.
Try $.each() to iterate through the list(assuming it is an array), so that the callback passed will create a separate closure for each iteration
$.each(linkList, function (i, item) {
$.ajax({
url: item.getAttribute("href"),
cache: false
}).done(function (html) {
var hasAppended = false;
if (html.indexOf('someStringOnGottenPage') != -1 && !hasAppended) {
hasAppended = true;
var id = item.getAttribute("href").substring(item.getAttribute("href").indexOf('='));
$("#links a[href*='" + id + "']").append(' THIS PAGE CONTAINS SPECIFIED DATA');
}
});
})
If it is an jQuery object then use .each()
linkList.each(function (i, item) {
var $item = $(item),
href = $item.attr("href");
$.ajax({
url: href,
cache: false
}).done(function (html) {
var hasAppended = false;
if (html.indexOf('someStringOnGottenPage') != -1 && !hasAppended) {
hasAppended = true;
var id = href.substring(href.indexOf('='));
$("#links a[href*='" + id + "']").append(' THIS PAGE CONTAINS SPECIFIED DATA');
}
});
})
Related videos on Youtube
Edge
Updated on November 12, 2020Comments
-
Edge over 3 years
I'm new to using AJAX, and I'm writing a userscript that will process a bunch of links on a page and make AJAX calls for each one.
for (var i = 0; i < linkList.length; i++) { $.ajax({ url: linkList[i].getAttribute("href"), cache: false }).done(function( html ) { var hasAppended = false; if (html.indexOf('someStringOnGottenPage') != -1 && !hasAppended) { hasAppended = true; var id = linkList[i].getAttribute("href").substring(linkList[i].getAttribute("href").indexOf('=')); $( "#links a[href*='" + id + "']" ).append(' THIS PAGE CONTAINS SPECIFIED DATA'); } }); }
To try to put it simply, I have a page with a list of links. I wish to iterate through the links and get AJAX to process the contents of each of the links pages, and report back if that page contains something specified.
The issue I'm having is the value of [i] used to iterate through the linkList is always 6, and it should never be. I'm assuming I need to pass some data so that when .done finally triggers, it knows its [i] value from when AJAX first triggered and not the value of [i] when .done triggers later.
How do I go about ensuring .done knows it's [i] value when AJAX is first called?
-
Arun P Johny over 10 years
-
Arun P Johny over 10 yearswhat is
linkList
is it a jQuery object or a array? -
Arun P Johny over 10 yearsthe solution might look something like jsfiddle.net/arunpjohny/2Da7Z/1
-
-
Edge over 10 yearsAdding the (function (i) { CODE })(i); wrapper works perfectly, now the code runs with the intended result. Thankyou!
-
LazerSharks almost 10 yearsSo THAT's the point of a closure
-
krummens about 7 yearsyou saved my life
-
Pedro Joaquín over 4 yearsIt throws: "async its not defined"
-
Amadan over 4 years@PedroJoaquin: For one thing, the answer was written before
async
was a keyword. For another, this is a pseudocode, andasync
was a metavariable here, standing for any asynchronous function that accepts a callback, just likeuse()
is a metavariable for any task that should be done inside a callback. I will renameasync
to make it compatible with ES6, but you still have to replace with function you are actually using (such as$.ajax
in the OP).