javascript - que - async.js obtienen cada índice en el iterador
what is function*in javascript (5)
Actualizar
Desde que escribí esta respuesta, ahora hay una mejor solución. Por favor, vea la respuesta de xuanji para más detalles
Original
Gracias a @genexp por un ejemplo simple y conciso en los comentarios a continuación ...
async.each(someArray, function(item, done){
console.log(someArray.indexOf(item));
});
Después de leer los documentos, sospeché que no había forma de acceder a una posición que representara un número entero en la lista ...
Aplica una función de iterador a cada elemento de una matriz, en paralelo . Se llama al iterador con un elemento de la lista y una devolución de llamada cuando finaliza. Si el iterador pasa un error a esta devolución de llamada, la devolución de llamada principal para cada función se llama inmediatamente con el error.
Tenga en cuenta que, dado que esta función aplica el iterador a cada elemento en paralelo, no hay garantía de que las funciones del iterador se completen en orden.
Así que cavé un poco más profundo ( enlace del código fuente )
async.each = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
_each(arr, function (x) {
iterator(x, only_once(function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback(null);
}
}
}));
});
};
Como puede ver, hay un recuento completed
que se actualiza a medida que se completa cada devolución de llamada, pero sin una posición de índice real.
Por cierto, no hay ningún problema con las condiciones de carrera en la actualización del contador completed
ya que JavaScript es puramente de un solo hilo bajo las sábanas.
Editar: después de profundizar en el iterador, parece que es posible que pueda hacer referencia a una variable de index
gracias a los cierres ...
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
Estoy usando la biblioteca async.js de caolan , específicamente el método .each.
¿Cómo se obtiene acceso al índice en el iterador?
async.each(ary, function(element, callback){
//do stuff here for each element in ary
//how do I get access to the index?
}, function(err) {
//final callback here
})
- La solución de indexOf es lenta y no debe usarse para arreglos grandes.
- cada solución Serial de Merc no hace lo que quiere.
- La solución efectiva es simplemente construir otra matriz con índices:
someArrayWithIndexes = someArray.map(function(e, i) {return {obj: e, index: i}}); async.each(someArrayWithIndexes , function(item, done){ console.log("Index:", item.index); console.log("Object:", item.obj); });
El método async.each()
repetirá la matriz en paralelo y no proporciona el índice del elemento a la devolución de llamada iterativa.
Entonces cuando tienes:
function( done ){
async.each(
someArray,
function( item, cb ){
// ... processing
cb( null );
},
function( err ){
if( err ) return done( err );
// ...
done( null );
}
);
}
Si bien PODRÍA usar Array.indexOf()
para encontrarlo:
function( done ){
async.each(
someArray,
function( item, cb ){
// ... processing
var index = someArray.indexOf( item );
cb( null );
},
function( err ){
if( err ) return done( err );
// ...
done( null );
}
);
}
Esto requiere una búsqueda en la memoria en la matriz para CADA iteración de la matriz. Para matrices de gran tamaño, esto puede ralentizar bastante todo.
Una mejor solución alternativa podría ser utilizar async.eachSeries()
y realizar un seguimiento del índice usted mismo:
function( done ){
var index = -1;
async.eachSeries(
someArray,
function( item, cb ){
// index is updated. Its first value will be `0` as expected
index++;
// ... processing
cb( null );
},
function( err ){
if( err ) return done( err );
// ...
done( null );
}
);
}
Con cada eachSeries()
, tiene la garantía de que todo se hará en el orden correcto.
Otra solución, que es la primera opción del mantenedor de la asincrónica , es iterar con Object.keys:
function( done ){
async.each(
Object.keys( someArray ),
function( key, cb ){
// Get the value from the key
var item = someArray[ key ];
// ... processing
cb( null );
},
function( err ){
if( err ) return done( err );
// ...
done( null );
}
);
}
Espero que esto ayude.
Puede usar async.forEachOf
: llama a su devolución de llamada de iterador con el índice como su segundo argumento.
> async.forEachOf([''a'', ''b'', ''c''], function () {console.log(arguments)});
{ ''0'': ''a'', ''1'': 0, ''2'': [Function] }
{ ''0'': ''b'', ''1'': 1, ''2'': [Function] }
{ ''0'': ''c'', ''1'': 2, ''2'': [Function] }
ver los docs para más información
Solo yse async.forEachOf :
async.forEachOf(arr, function(value, index, callback) { ... },...
Ver documentación here .