He estado haciendo bastante de eso en un proyecto reciente. He escrito un código para ayudar a administrarlo. Aquí está el código. Usted pasa la función bundledAsync a un objeto con un parámetro "calls" y un parámetro "bundleCallback". El parámetro de llamadas es una matriz de objetos que representa la función que desea llamar. En el parámetro fn, almacena una referencia al parámetro real. En el parámetro "args", almacenas tus argumentos. El último argumento de cada una de las funciones que pasa debe ser una devolución de llamada, que debe ser llamada.
Me siento miserable al documentar mi código y hacer que sea útil para otros, pero esto es realmente realmente útil para mí. Sospecho que alguien más ha escrito algo similar, tal vez debidamente documentado. Si no puede encontrarlo, y necesita ayuda para resolverlo, hágamelo saber.
/**
This is a way to submit multiple async calls, and be notified when they've all finished
<pre>
NameSpace.bundledAsync({
calls:[
{
fn: service.getGroups,
args: [
function(listsArg){
listsSummary = listsArg;
}
],
calls: function(){return UNAB.Util.makeArray(listsSummary, function(list){
return {
fn: service.getGroup,
args: [list.id, function(resp){listsDetail.push(resp)}]
}
})}
}
],
bundleCallback: function(){
callback(listsDetail)
}
});
</pre>
@class bundledAsync
@static
*/
NameSpace.bundledAsync = function(options){
var callbacksLeft = 0;
var calls = $.grep(options.calls, function(call){return call});
if(options.hasOwnProperty("bundleCallback") && typeof options.bundleCallback != "function"){
throw new Error("bundleCallback, passed to bundledAsync, must be a function.");
}
if(options.chain){ // if this is true, sibling calls will run in succession, not in parallel
calls.reverse();
var newCalls = [calls.pop()];
var lastCall = newCalls[0];
while(calls.length > 0){
if(lastCall.calls){
throw new Error("You can't nest calls if you're in chain mode");
}
lastCall.calls = [calls.pop()];
lastCall = lastCall.calls[0];
}
calls = newCalls;
}
var decrimentCallbacksLeft = function(){
if(options.name){
// log.debug("Starting decrimentCallbacksLeft for: " + options.name + ". Decrimenting callbacksLeft to: " + (callbacksLeft - 1));
}
if(--callbacksLeft == 0 && options.bundleCallback){
// log.debug("No callbacks left. Calling bundleCallback for name: " + options.name);
options.bundleCallback();
}
}
var doCalls = function(callsToDo){
if(typeof callsToDo == "function"){
callsToDo = callsToDo();
}else{
callsToDo = $.extend(true, [], callsToDo);// in case we want to reuse the calls
}
// right away, return if the calls are empty
// check to make sure callbacksLeft == 0, because
// we may be dealing with nested calls
if(callsToDo.length ==0 && callbacksLeft == 0){
// log.debug("callsToDo is empty, so call the callback right away.");
options.bundleCallback();
return null;
}
callbacksLeft += callsToDo.length;
$.each(callsToDo, function(index, call){
var numFns = 0;
// // Look through the args searching for functions.
// // When one is found, wrap it with our own function.
// // This assumes that each function has exactly one
// // callback, and that each callback is called exactly once
// args can be a function which will return the args,
// that way, you don't have to determine the args for the function until the moment it's called
call.args = call.jitArgs? call.args():call.args;
$.each(call.args, function(index, arg){
if(typeof arg === "function"){
numFns++;
// Here's where we wrap the original function's callback
call.args[index] = function(){
// when we get to this point, we know that the original function has totally completed,
// and we can call any functions chained to this one, or finish the whole process
arg.apply(null, arguments); // call the original callback
if(call.calls){
// maybe we don't want to create the child calls until after
// the parent has returned. In that case, pass a function instead of an array
if(typeof call.calls === "function"){
call.calls = call.calls();
}
// if this call has any call of its own, send those out now
doCalls(call.calls);
}
decrimentCallbacksLeft();
}
}
});
if(numFns!=1){
throw new Error("Each function passed to bundledAsync must have one and only one arg which is a function");
}
// if(call.fn.length != call.args.length){
// log.warn("The current function is being called with a different number of arguments that that with which it was declared. Should be: "+call.fn.length+", was: "+call.args.length+" \n" + call.fn.toString());
// }
call.fn.apply(null, call.args);
});
}
doCalls(calls);
}
... ¿podría explicar con más detalle lo que quiere hacer? – deceze
Me gustaría escribir este control de flujo, pero no sé cómo. Busqué mucho código, pero no lo conseguí. –
¿Las funciones son potencialmente asincrónicas? – slebetman