2011-03-14 4 views
7

Esto es principalmente una pregunta independiente del idioma.código de ejecución cuando dos eventos han desencadenado

Si estoy esperando que se lleven a cabo dos eventos (por ejemplo, dos eventos IO o solicitudes http), ¿cuál es el mejor patrón para tratar esto? Una cosa en la que puedo pensar es la siguiente (ejemplo de pseudo js).

request1.onComplete = function() { 
    req1Completed = true; 
    eventsCompleted(); 
} 

request2.onComplete = function() { 
    req2Completed = true; 
    eventsCompleted(); 
} 

eventsCompleted = function() { 

    if (!req1Completed || !req2Completed) return; 
    // do stuff 

} 

¿Es este el patrón más efectivo, o hay formas más elegantes de resolver este problema?

+6

¿Está esperando que estos eventos ocurran en un orden en particular? Eso afecta la solución en gran medida. –

+0

No, cualquier orden posible – Evert

Respuesta

4

Antes incluso de entrar en los detalles, aquí hay algo limpio que se aprovecha de las funciones lambda de la parte superior de mi cabeza:

function makeCountdownCallback(count, callback) { 
    return function() { 
     if (--count == 0) 
      callback(); 
    }; 
} 

request1.onComplete = request2.onComplete = makeCountdownCallback(2, function() { 
    // do stuff 
}); 

Obviamente, esto supone que cada evento se desencadena como máximo una vez, y no toma ventaja de la orden

+0

Esta solución es mejor si tiene una cantidad arbitraria de eventos que está esperando, pero el hecho de que solo funcione si los eventos ocurren * una vez * es un poco peligroso. –

+1

Eso es un poco resbaladizo. Un poco loco, pero resbaladizo. –

+0

No es una mala solución; Este gana, aunque una parte de mí siente que es una solución un poco sucia :) – Evert

2

jQuery 1.5 tiene Deferreds: http://api.jquery.com/category/deferred-object/

podrá ajustar fácilmente hacia arriba para volver a llamar sólo cuando algunos eventos se han disparado.

+0

Un "diferido" es definitivamente algo a considerar.Le permite hacer una interfaz bastante ordenada para rastrear múltiples devoluciones de llamadas, algo similar a 'afterAllOfThese (def1, def2, def2, function() {...})' ... a menos que, por supuesto, jQuery ya tenga algo para esperar para eventos múltiples –

+0

Estoy esperando una solución genérica, aplicable a múltiples idiomas. – Evert

1

Try # 1: He aquí una solución que no requiere variables globales adicionales:

request1.onComplete = function() { 
    // register new handler for event2 here, overwriting the old one 
    request2.onComplete = function() { 
     // now they're both done 
    } 
} 

request2.onComplete = function() { 
    // register new handler for event1 here, overwriting the old one 
    request1.onComplete = function() { 
     // now they're both done 
    } 
} 

El controlador para el que sea activa el evento de primera borrará de edad manejador del otro y asignar una nueva que incluye la cosas que debe hacer después de la finalización de ambos eventos. Debido a que reasignamos el segundo controlador dentro del controlador del primer evento (cualquiera que sea), siempre sabemos que terminamos cuando el segundo controlador finaliza.

Try # 2: Aquí hay algo que va a funcionar si cada tipo de evento es diferente:

function onBoth(fn) { 
    var last, done = false; 
    return function(e) { 
     if (last && last !== e.type && !done) { 
      fn(); // done 
      done = true; 
     } 
     last = e.type; 
    } 
} 

Por ejemplo, esto no le alertará "hecho" cuando el usuario haya tanto desplazado clic:

var both = onBoth(function() { 
    alert("done") 
}); 

document.addEventListener("scroll", both, false); 
document.addEventListener("click", both, false); 

try # 3: El intento anterior puede ser modificado para trabajar por eventos similares:

function onBoth(fn) { 
    var last, done = false; 
    return function(curr) { 
     if (last && last !== curr && !done) { 
      fn(); // done 
      done = true; 
     } 
     last = curr; 
    } 
} 

... que debe ser utilizado de esta manera:

var check = onBoth(function() { 
    alert("done") 
}); 

request1.onComplete = function() { 
    check(arguments.callee); 
} 

request2.onComplete = function() { 
    check(arguments.callee); 
} 

Básicamente, se comprueba que dos devoluciones de llamada diferentes han ejecutado mediante el almacenamiento de una referencia a la llamada más recientemente ejecutado espalda. Su uso es un poco torpe, pero hace el trabajo (es decir, seguirá funcionando si cada uno de los eventos se ejecuta más de una vez).

+0

'request1' y' request2' me parecen bastante globales –

+0

@Matti - Por supuesto que sí. Claramente quise decir que no requiere banderas globales adicionales para indicar que cada controlador ha terminado. –

Cuestiones relacionadas