2011-10-13 11 views
22

Tengo un controlador de eventos, pero quiero asegurarme de que esperará hasta que se hayan ejecutado todos los demás eventos en la cola de eventos.Cómo ejecutar código después de que se hayan manejado todos los demás eventos

Por ejemplo, tengo algunas pestañas en una página. Tengo un código general para manejar las pestañas que establece una pestaña en "Pestaña activa" cuando un usuario hace clic en ella.

$('a.tab').click(function() { 
    $(this).parent('div').find('a.tab').removeClass('activeTab'); 
    $(this).addClass('activeTab'); 
}); 

Para un conjunto específico de pestañas, que podría tener un manejador:

// handler-1 
$('div#myTabs a.tab').click(function() { 
    do_something(); 
}); 

function do_something() { 
    var type = $('div#myTabs a.activeTab').data('type'); 
    do_something_else(type); 
} 

hacer_algo() puede ser llamado en respuesta a otras acciones además de hacer clic en una pestaña, pero independientemente de cómo se se invoca, quiere saber qué es la pestaña activa antes de que pueda continuar.

Mi problema es que si se invoca mediante el código en '// handler-1', la clase 'activeTab' puede no haberse restablecido todavía, por lo que el valor que recupera para 'type' seguirá siendo de cualquier etiqueta que se haya seleccionado antes de hacer clic en esta.

Lo resuelto de esta manera:

// handler-1 
$('div#myTabs a.tab').click(function() { 
    set_timeout(function() { 
    do_something(); 
    }, 100); 
}); 

Esto parece demasiado de un kludge para satisfacerme. ¿Cómo sé que solo se llamará al controlador de eventos del temporizador después de que todos los demás controladores hayan tenido su turno? Claro que podría cambiar "100" por "1000" o incluso "10000", pero también estaría operando para mayor certeza (y aún no hay certeza, ya que incluso 10 segundos pueden no ser suficientes en una instancia de navegador en una máquina que lisiado lo suficiente).

que he visto varias soluciones posibles:

pero ninguno de estos son lo suficientemente generales como para satisfacerme. No estoy tratando de obtener un controlador para ejecutar primero. Más bien, quiero algo como esto:

function do_something() { 
    $.when_all_other_events_have_been_handled(function() { 
    do_something(); 
    }); 
}); 

¿Algo como esto existe?

Miré $ .fn.when (arg) .done(), pero ¿cuándo? "arg" en este caso debería ser un objeto diferido que ejecuta lo que ya está en la cola de ejecución. Un Catch-22!

Sproutcore tiene algo así como "engine.run()" (no recuerdo el nombre exacto) que volverá solo cuando se hayan manejado todos los demás eventos en el "motor", pero no puedo encontrar nada como eso en jQuery. (http://api.jquery.com/category/events/). Si alguien sabe de algo así, ¡por favor házmelo saber!

Gracias! :)

Respuesta

27

Prueba esto:

function postpone(fun) 
{ 
    window.setTimeout(fun,0); 
} 

por lo que si va a llamar postpone(do_something); que do_something se ejecutará después de todos los eventos de interfaz de usuario que se encuentran en la cola de eventos para el momento de postpone() llamada.

+0

¡Oye! ¡Me ganaste a mi propia respuesta! –

+1

Estaba usando esto con un tiempo de espera positivo y pensé que era una condición de carrera, me alegré de ver que es válido :) – Jake

+0

Faced error cuando se usa la función de posponer: error inútil llamada setTimeout (¿falta de comillas en el argumento?) En FireFox 20.0 para Ubuntu canónico 1.0. @ Lsiden respuesta funcionó para mí. –

25

que puede haber encontrado la respuesta aquí: http://ejohn.org/blog/how-javascript-timers-work/

Según J.Resig, si lo hago

setTimeout(function() { 
    do_something(); 
}, 0); 

la función anónima conseguirá enqued de inmediato, pero no se llamará hasta que todo lo demás en la cola de eventos ya se ha manejado. Es decir, siempre y cuando el navegador en el que se ejecuta realmente ejecute todo según el principio de "primero en entrar, primero en salir", como yo esperaba. Si por alguna razón el motor de Javascript se encarga de volver a ordenar los eventos en la cola (no sé por qué debería hacerlo, pero nunca se sabe desde AFAIK nunca he visto ninguna garantía en los estándares, pero luego necesito mirar de nuevo) ¡entonces todas las apuestas están apagadas!

+0

No veo este comportamiento con Chrome en este momento. Tengo 2 funciones separadas llamadas en el evento "clic" de una casilla de verificación. En el último que quiero, lo envolví en el setTimeout, pero si lo configuro en 0 ... parece ser una condición de carrera. Lo configuré en 500 y parece funcionar, pero me temo que es solo por suerte. – Dss

Cuestiones relacionadas