jQuery AJAX llama para el bucle

Soy nuevo en el uso de AJAX, y estoy escribiendo un usuario que procesará un grupo de enlaces en una página y hará llamadas AJAX para cada uno.

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'); } }); } 

Para tratar de decirlo simplemente, tengo una página con una lista de enlaces. Deseo iterar a través de los enlaces y obtener AJAX para procesar los contenidos de cada una de las páginas de enlaces, e informar si esa página contiene algo específico.

El problema que estoy teniendo es el valor de [i] usado para iterar a través del linkList siempre es 6, y nunca debería ser. Supongo que necesito pasar algunos datos para que cuando .done finalmente se active, sepa su valor [i] desde cuando AJAX se activó por primera vez y no el valor de [i] cuando .done se desencadena más tarde.

¿Cómo puedo asegurarme de que .done sepa que es [i] valioso cuando se llama por primera vez a AJAX?

La forma más fácil es usar un cierre. Siempre que tenga algo asincrónico en un bucle, es lo mismo.

 for (var i .....) { async(function() { use(i); } } 

En este fragmento de pseudocódigo, la función interna captura la ubicación de almacenamiento a la que hace referencia i . El bucle se ejecuta, i aumenta a su valor final y luego se activan las devoluciones de llamada asincrónicas, todas buscando la misma ubicación exacta (no el valor).

La solución general es esta:

 for (var i .....) { (function (i) { async(function() { use(i); }); })(i); } 

es decir, envuelve todo el contenido de tu bucle en una función autoejecutable.

Aquí, el valor de outer i pasa a la función anónima autoejecutable de envoltura; la ubicación de este valor único es capturada por la callback asíncrona. De esta forma, cada asincrónica obtiene su propio valor, determinado en el momento en que se invoca la función autoejecutable.

Los enlaces en la sección de comentarios de la pregunta le dicen qué está mal en su código … pero puede tener una solución mejor que la que se explicó allí.

Pruebe $ .each () para recorrer la lista (suponiendo que sea una matriz), de modo que la callback genere un cierre separado para cada iteración

 $.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'); } }); }) 

Si es un objeto jQuery, utiliza .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'); } }); })