2011-03-05 14 views
5

Antes de sumergirme en la pregunta. Permítanme decir que por Event Loop me refiero al http://en.wikipedia.org/wiki/Event_loop. Esto es algo que implementan los navegadores. Para obtener más información, lea esto: http://javascript.info/tutorial/further-javascript-features/events-and-timing-depth.No entiendo completamente JavaScript Threading

Esta pregunta es difícil y larga, por lo tanto, intente soportarlo. ¡Y aprecio todas las respuestas!


So. Ahora, según tengo entendido, en JavaScript hay un solo hilo principal (en la mayoría de los entornos de navegador, eso es). Por lo tanto, un código como:

for (var color = 0x000; color < 0xfff; color++) { 
    $('div').css('background-color', color.toString(16)); 
} 

producirá una animación del negro al blanco, pero no se verá que debido a que la prestación se realiza después de que el código ha sido procesado (cuando el próximo garrapata sucede - el el navegador ingresa al bucle de evento).

Si quieres ver la animación, se puede hacer:

for (var color = 0x000; color < 0xfff; color++) { 
    setTimeout(function() { 
     $('div').css('background-color', color.toString(16)); 
    }, 0); 
} 

el ejemplo anterior puede producir una animación visible, ya que empuja setTimeout un nuevo evento para el navegador pila Evento bucle que será procesada después de que haya no se está ejecutando nada (ingresa al bucle de eventos para ver qué hacer a continuación).

Parece que el navegador en este caso tiene eventos 0xfff (4095) insertados en la pila, donde cada uno de ellos se procesa con un proceso de renderizado entre ellos. Entonces, mi primera pregunta (n. ° 1) es ¿cuándo exactamente tiene lugar la representación? ¿Siempre tiene lugar entre el procesamiento de dos eventos en la pila de eventos de bucle?


La segunda pregunta es sobre el código en el enlace del sitio javascript.info que te di.

... 
    function func() { 
    timer = setTimeout(func, 0) 
    div.style.backgroundColor = '#'+i.toString(16) 
    if (i++ == 0xFFFFFF) stop() 
    } 

timer = setTimeout(func, 0) 
.... 

Mi pregunta aquí es que el navegador va a impulsar un nuevo evento "representación" al bucle de eventos pila cada vez que llegue a la línea div.style. ... = ...? Pero, ¿no impulsa primero un evento debido a la llamada a setTimeout? Por lo tanto, termina el navegador en una pila como:

setTimeout event 
render event 

Desde la llamada setTimeout se procesó antes de que el cambio de estilo de div? Si es así como la pila se parece, entonces yo asumiría la próxima vez que el navegador entra en el bucle de eventos que procesará devolución de llamada del setTimeout y llegar a tener:

rendering event 
setTimeout event 
rendering event 

y continuar con el evento de renderizado que la llamada setTimeout anteriormente producido?

Respuesta

6

Q1: No necesariamente. Los navegadores en distintos grados implementan optimizaciones. Por ejemplo, pueden esperar para recopilar varios cambios de estilo antes de desencadenar un costoso recálculo del diseño. Entonces la respuesta es: depende del navegador específico.

Prueba esto: http://taligarsiel.com/Projects/howbrowserswork1.htm#Render_tree_construction (el documento está fechado octubre 2009 - es decir, es suficientemente actualizadas)

P2: La prestación no es necesariamente la misma que la ejecución JS - eso es dos motores diferentes. El motor JS de Ths no es responsable de la representación, simplemente interactúa con el motor de renderizado.Me parece que el mensaje principal para su segunda pregunta es la independencia del JS del motor de representación. Recuerde, un navegador (o una página web) no necesita Javascript, su objetivo principal es renderizar HTML basado en reglas de estilo CSS. Javascript es solo una forma de manipular el HTML (el árbol DOM realmente) y las reglas de estilo.

Tenga en cuenta que puede forzar la representación leyendo una definición de estilo: en este punto, el motor de renderizado no tiene otra opción que procesar cualquier cambio de estilo sobresaliente, especialmente si implica algún cambio de posición. Es por eso que uno debe eliminar objetos del árbol de renderizado (por ejemplo, configurando display: none - visibility: hidden NO es suficiente ya que el tamaño del elemento aún se considera para el diseño) antes de hacer muchos cambios de estilo o agregar muchos elementos, p. cuando se agregan muchas filas una por una (un bucle "for") a una tabla.

No es parte de la pregunta en absoluto, pero como acabo de mencionar una diferencia entre display: none y visibility: hidden, eso también es una consideración al agregar posición oculta: elementos absolutos como los diálogos. Si bien no existe una diferencia visible entre un elemento posicionado y uno u otro, existe una gran diferencia: cuando se oculta con visibilidad: oculto, el elemento es parte del árbol de representación, con visualización: ninguno es no. Por lo tanto, si uno tiene un elemento de este tipo que necesita ser cambiado mucho, debe usar visibilidad: oculto, porque cuando el estilo de "visualización" se cambia entre "ninguno" y p. "bloquear" el navegador tiene que renderizarlo primero.

+0

1 para el enlace a 'cómo funcionan los navegadores' :-) – Martijn

1

El artículo que menciona solo considera Javascript. Sucede mucho más en el navegador; el refinado y el repintado son/pueden ser desencadenados por muchas cosas más; echa un vistazo a los siguientes enlaces para obtener más información sobre esto.

yo no usaría setTimeout para este propósito.

Editar: Según los comentarios, la forma recomendada es utilizar requestAnimationFrame. Al escribir estas líneas, esto solo está disponible en versiones inestables de la mayoría de los navegadores. Sin embargo, hay severallibraries disponibles que proporcionan acceso entre varios navegadores, y recurrir a setTimeout si es necesario.

Echa un vistazo a esta demo para un ejemplo de trabajo en los navegadores antiguos, así como en otros nuevos: http://paulirish.com/2011/requestanimationframe-for-smart-animating/

+0

En respuesta a la última frase : Para lograr la animación (es decir, cambiar uno o más atributos de estilo CSS a lo largo del tiempo) debería usar setTimeout, de lo contrario: 1) la ejecución bloquea el motor JS (y el navegador!), 2) ningún cambio visible (salta al final del animación sin pasos intermedios) porque el motor de representación optimizado detecta muchos cambios de estilo y recoge la mayoría o todos ellos antes de desencadenar una nueva representación. –

+0

Tienes razón, lo siento. Leí mal la pregunta (y me confundí con otra pregunta que estaba leyendo en ese momento). – Martijn

+0

En realidad, uno debe usar 'window.requestAnimationFrame()' si eso está disponible. – Tower