2012-04-24 11 views
14

¿Cuál es la mejor forma/biblioteca para gestionar múltiples devoluciones de llamada asincrónicas? En este momento, tengo algo como esto:Javascript - ¿esperando a que vuelvan varias devoluciones de llamada asincrónicas?

_.each(stuff, function(thing){ 
    async(thing, callback); 
}); 

necesito para ejecutar algún código después de la devolución de llamada se ha disparado para cada elemento de stuff.

¿Cuál es la forma más limpia de hacer esto? Estoy abierto a usar bibliotecas.

+0

posible duplicado de [Esperando en asíncrona de varias llamadas para completar antes de continuar] (http://stackoverflow.com/questions/2768293/waiting-on-multiple-asynchronous-calls-to-complete-before-continuing) – RMalke

Respuesta

12

Hay una gran biblioteca llamada Async.js que ayuda a resolver problemas como este con muchos asincrónicos & ayudantes de control de flujo. Proporciona varios para cada función que puede ayudarle a ejecutar devoluciones de llamada para cada elemento en una matriz/objeto.

Salida: https://github.com/caolan/async#forEach

// will print 1,2,3,4,5,6,7,all done 

var arr = [1,2,3,4,5,6,7]; 

function doSomething(item, done) { 
    setTimeout(function() { 
    console.log(item); 
    done(); // call this when you're done with whatever you're doing 
    }, 50); 
} 

async.forEach(arr, doSomething, function(err) { 
    console.log("all done"); 
}); 
+0

Esto es bueno, y si esto puede manejar el encadenado para mí, puedo hacer este cambio más tarde. ¿Esto hace algo más inteligente que simplemente usar un contador como _.después? –

+0

Lo bueno es que puedes hacer 'async.forEachSerial' si quieres que se ejecuten uno tras otro. Te da flexibilidad.Para un caso de uso simple, sí, el recuento funciona muy bien y está integrado en el guión bajo. ¡Hazlo! –

+0

Terminé necesitando usar 'series' bastante, y cambiar a asincrónico limpió las cosas * bastante * un poco. También estoy bastante seguro de que descubrí un problema de tiempo de devolución de llamada en el proceso. –

0

Tienen un contador, digamos async_count. Aumente en uno cada vez que inicie una solicitud (dentro de su ciclo) y haga que la devolución de llamada la reduzca en uno y compruebe si se ha alcanzado el cero; de ser así, todas las devoluciones de llamada han regresado.

EDITAR: Aunque si yo fuera el que escribía esto, encadenaría las solicitudes en lugar de ejecutarlas en paralelo; en otras palabras, tengo una cola de solicitudes y hago que la devolución de llamada compruebe la cola para la próxima solicitud de hacer.

28

Puesto que usted ya está usando subrayado lo podría hacer en _.after. Hace exactamente lo que estás pidiendo. A partir de los documentos:

después       _.after(count, function)

Crea una versión de la función que sólo se ejecutará después de la primera siendo llamados tiempos de conteo. Útil para agrupar respuestas asincrónicas, donde desea asegurarse de que todas las llamadas asíncronas hayan terminado, antes de continuar.

+1

Esto funciona genial. –

2

Recomiendo https://github.com/caolan/async para esto. Puede usar async.parallel para hacer esto.

function stuffDoer(thing) { 
    return function (callback) { 
     //Do stuff here with thing 
     callback(null, thing); 
    } 
} 

var work = _.map(stuff, stuffDoer) 
async.parallel(work, function (error, results) { 
    //error will be defined if anything passed an error to the callback 
    //results will be an unordered array of whatever return value if any 
    //the worker functions passed to the callback 
} 
+0

¿Por qué no 'async.forEach'? –

+0

Creo que en este caso async.forEach y async.parallel son básicamente idénticos. Los documentos en para cada uno incluso dicen "los ejecuta en paralelo". Sin embargo, el nombre "paralelo" lo aclara. –

+0

Hmm, sí, parece que cada uno es más apropiado en este caso, ya que manejará los cierres por usted y puede simplemente darle una función regular y una lista de datos. –

1

async.parallel()/async.series debe ajustarse a sus necesidades. Puede proporcionar una devolución de llamada final que se ejecuta cuando todas las llamadas REST tienen éxito.

async.parallel([ 
    function(){ ... }, 
    function(){ ... } 
], callback); 
async.series([ 
    function(){ ... }, 
    function(){ ... } 
], callback); 
Cuestiones relacionadas