Espero no hacer el ridículo, pero estoy tratando de entender qué está sucediendo en esas dos líneas de código:
document.body.innerHTML = 'something';
alert('something else');
Lo que estoy observando es que la alerta se muestra antes de que se actualice HTML (o tal vez lo haya hecho, pero la página no se ha actualizado / repintado / lo que sea)
Consulte este codepen para ver a qué me refiero.
Tenga en cuenta que incluso poniendo alert
en setTimeout(..., 0)
no ayuda. Parece que se necesitan más bucles de eventos para innerHTML
actualizar la página.
EDITAR:
Olvidé mencionar que estoy usando Chrome y no verifiqué otros navegadores. Parece que solo está visible en Chrome. Sin embargo, todavía estoy interesado en por qué está sucediendo eso.
javascript
html
google-chrome
dom
cada uno
fuente
fuente
Respuestas:
La configuración de innerHTML es sincrónica, al igual que la mayoría de los cambios que puede realizar en el DOM. Sin embargo, renderizar la página web es una historia diferente.
(Recuerde, DOM significa "Document Object Model". Es solo un "modelo", una representación de datos. Lo que el usuario ve en su pantalla es una imagen de cómo debería verse ese modelo. Por lo tanto, cambiar el modelo no es instantáneo cambiar la imagen; la actualización lleva algún tiempo).
La ejecución de JavaScript y la representación de la página web en realidad ocurren por separado. Para decirlo de manera simplista, primero se ejecuta todo el JavaScript en la página (desde el bucle de eventos; vea este excelente video para obtener más detalles) y luego, después de eso, el navegador muestra cualquier cambio en la página web para que el usuario lo vea. Esta es la razón por la que "bloquear" es tan importante: ejecutar código computacionalmente intensivo evita que el navegador pase del paso "ejecutar JS" y entre en el paso "renderizar la página", lo que hace que la página se congele o tartamudee.
La canalización de Chrome se ve así:
Como puede ver, todo el JavaScript ocurre primero. Luego, la página recibe estilo, diseño, pintura y composición: el "render". No toda esta canalización ejecutará todos los marcos. Depende de los elementos de la página que hayan cambiado, si es que hubo alguno, y de cómo deben volver a reproducirse.
Nota:
alert()
también es síncrono y se ejecuta durante el paso de JavaScript, por lo que el cuadro de diálogo de alerta aparece antes de que vea los cambios en la página web.Ahora podría preguntar "Espera, ¿qué se ejecuta exactamente en ese paso de 'JavaScript' en la canalización? ¿Todo mi código se ejecuta 60 veces por segundo?" La respuesta es "no", y se remonta a cómo funciona el bucle de eventos JS. El código JS solo se ejecuta si está en la pila, desde elementos como detectores de eventos, tiempos de espera, lo que sea. Ver video anterior (de verdad).
https://developers.google.com/web/fundamentals/performance/rendering/
fuente
Sí, es sincrónico, porque esto funciona (adelante, escríbalo en su consola):
La razón por la que ve la alerta antes de ver el cambio de página es que la renderización del navegador lleva más tiempo y no es tan rápida como su javascript ejecutándose línea por línea.
fuente
text
en mi ejemplo) Eso responderá a su pregunta de si es sincrónico. La representación del navegador frente a la ejecución de Javascript es manzana y naranja :)La
innerHTML
propiedad real se actualiza de forma sincrónica, pero el rediseño visual que provoca este cambio ocurre de forma asincrónica.La representación visual del DOM es asíncrona en Chrome y no sucederá hasta que la pila de funciones de JavaScript actual se haya borrado y el navegador sea libre de aceptar un nuevo evento. Otros navegadores pueden usar subprocesos separados para manejar el código JavaScript y la representación del navegador, o pueden permitir que algunos eventos tengan prioridad mientras una alerta detiene la ejecución de otro evento.
Puedes ver esto de dos formas:
Si agrega
for(var i=0; i<1000000; i++) { }
antes de su alerta, le ha dado al navegador suficiente tiempo para volver a dibujar, pero no lo ha hecho, porque la pila de funciones no se ha borrado (add
todavía se está ejecutando).Si retrasa su
alert
vía asincrónicasetTimeout(function() { alert('random'); }, 1)
, el proceso de redibujo se adelantará a la función retrasada por setTimeout.0
, posiblemente porque Chrome da prioridad de cola de eventos a los0
tiempos de espera antes de cualquier otro evento (o al menos antes de los eventos de redibujo).fuente
setTimeout(func, 1)
no funcionó todas las veces, consulte este video: youtu.be/r8caVE_a5KQ