El bucle for
se ejecuta inmediatamente hasta su finalización mientras se inician todas las operaciones asincrónicas. Cuando completen algún tiempo en el futuro y llamen a sus devoluciones de llamada, el valor de su variable de índice de bucle i
estará en su último valor para todas las devoluciones de llamada.
Esto se debe a que el bucle for
no espera a que finalice una operación asincrónica antes de continuar con la siguiente iteración del bucle y porque las devoluciones de llamada asíncronas se invocan en el futuro. Por lo tanto, el bucle completa sus iteraciones y ENTONCES se llaman las devoluciones de llamada cuando terminan esas operaciones asincrónicas. Como tal, el índice de bucle está "listo" y se encuentra en su valor final para todas las devoluciones de llamada.
Para solucionar esto, debe guardar de forma exclusiva el índice de bucle por separado para cada devolución de llamada. En Javascript, la forma de hacerlo es capturarlo en un cierre de función. Esto se puede hacer creando un cierre de función en línea específicamente para este propósito (el primer ejemplo se muestra a continuación) o puede crear una función externa a la que le pase el índice y dejar que mantenga el índice exclusivamente para usted (segundo ejemplo se muestra a continuación).
A partir de 2016, si tiene una ejecución de Javascript totalmente hasta a la especificación ES6, también se puede utilizar let
para definir la variable de bucle for
y se definirá de forma única para cada iteración del bucle for
(tercera aplicación abajo). Sin embargo, tenga en cuenta que esta es una característica de implementación tardía en las implementaciones de ES6, por lo que debe asegurarse de que su entorno de ejecución sea compatible con esa opción.
Uso.forEach() para iterar ya que crea su propio cierre de función
someArray.forEach(function(item, i) {
asynchronousProcess(function(item) {
console.log(i);
});
});
Crear su propio cierre de función Utilizando un IIFE
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asynchronousProcess(function() {
console.log(cntr);
});
})(i);
}
crear o modificar Función externa y pasarlo de la variable de
Si puede modificar la función asynchronousProcess()
, entonces puede simplemente pasar el valor allí y tener el asynchronousProcess()
funcionan de la CNTR de nuevo a la devolución de llamada como esto:
var j = 10;
for (var i = 0; i < j; i++) {
asynchronousProcess(i, function(cntr) {
console.log(cntr);
});
}
Uso ES6 let
Si tiene un entorno de ejecución de Javascript que es totalmente compatible con ES6, puede utilizar let
en su for
bucle de la siguiente manera:
const j = 10;
for (let i = 0; i < j; i++) {
asynchronousProcess(function() {
console.log(i);
});
}
let
declaró en una declaración for
bucle como esto creará una uni que valor de i
para cada invocación del bucle (que es lo que desea).
de números de serie de promesas y asíncrono/esperan
Si su función asíncrona devuelve una promesa, y desea realizar una serie sus operaciones asíncronas para ejecutar uno tras otro en lugar de en paralelo y que se está ejecutando en un moderno entorno que admite async
y await
, entonces usted tiene más opciones.
async function someFunction() {
const j = 10;
for (let i = 0; i < j; i++) {
// wait for the promise to resolve before advancing the for loop
await asynchronousProcess();
console.log(i);
}
}
Esto se asegurará de que sólo una llamada a asynchronousProcess()
está en vuelo a la vez y el bucle for
ni siquiera avanzará hasta que cada uno se hace. Esto es diferente a los esquemas anteriores que ejecutaron todas sus operaciones asincrónicas en paralelo, por lo que depende completamente del diseño que desee. Nota: await
funciona con una promesa, por lo que su función debe devolver una promesa que se resuelve/rechaza cuando se completa la operación asincrónica. Además, tenga en cuenta que para usar await
, la función contenedora debe declararse async
.
¿Qué tal si agregamos el parámetro i a la función 'asynchronousProcess'? Que puede pasarlo a la función callbackFunction –
duplicación posible de [Javascript closure inside loops - ejemplo práctico simple] (http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) –