HeadlinesBriefing favicon HeadlinesBriefing.com

Rendimiento del Hilo Principal del Navegador

Hacker News •
×

¿Qué se te viene a la mente cuando oyes “optimización del frontend”? Para la mayoría de nosotros son cosas como reducir las peticiones de red, reducir el tamaño del paquete o hacer buen uso de la caché. Más allá de eso, tal vez reducir los re-renders o ajustar cuándo se cargan los recursos. El hilo principal no suele salir a colación, y hay una razón para ello: en la mayoría de las pantallas nunca se convierte en un problema.

Pero en pantallas con mucha interacción, donde los datos llegan en vivo y el desplazamiento, la animación y la entrada se entrelazan, la cosa cambia. Por mucho que ahorres en red y tamaño del paquete, la pantalla se congela en el momento en que el hilo principal se bloquea. Probablemente hayas encontrado un sitio web donde el desplazamiento tartamudea de vez en cuando, un botón responde con un ligero retraso o las letras que escribes en un cuadro de búsqueda aparecen medio latido tarde.

No es lo suficientemente malo como para ser molesto, pero te pone nervioso de forma sutil. Ese tipo de “jank” es lo que parece un hilo principal bloqueado. Cuando nos topamos con “jank” como este como desarrolladores, la reacción habitual es preguntarse “¿mi código es lento?” y empezar a diseccionar algoritmos o buscar cálculos desperdiciados.

En la mayoría de los casos, sin embargo, la velocidad del código no es el problema. El código no es lento. Simplemente resulta ser el código que está reteniendo el hilo principal.

El navegador tiene varios hilos, pero casi todo lo que podemos tocar desde el código se concentra en el hilo principal. Cálculo, renderizado, manejo de eventos, manejo de respuestas de red y los internos de tu framework se procesan allí. Un recurso, una montaña de trabajo.

El hilo principal del navegador es caro. La mayor parte del tiempo no causa problemas, pero una vez que intentas hacer algo ambicioso, lidiar con el hilo principal se convierte en la parte importante. Este artículo trata sobre cómo manejar ese recurso caro.

Empecemos con lo que el hilo principal realmente hace. Su trabajo cae en dos amplias categorías. La primera es ejecutar JavaScript.

El código que escribimos, junto con los manejadores de eventos, temporizadores, callbacks de respuesta de red y los internos del framework, todo se ejecuta aquí. Estas tareas se ejecutan en el orden en que entran en la cola, siempre que hay un hueco, sin relación con el ciclo de actualización de la pantalla. La segunda es dibujar la pantalla.

Cuando el DOM o los estilos cambian y la pantalla necesita actualizarse, el navegador pasa aproximadamente por estos pasos, en orden, para producir un fotograma. Ejecutar callbacks de requestAnimationFrame — JavaScript registrado para ejecutarse justo antes de que se dibuje el fotograma Cálculo de estilos — calcular los valores CSS finales para cada elemento Layout — calcular la posición y el tamaño de cada elemento (también llamado reflow) Paint — generar comandos de pintura describiendo qué dibujar, en qué colores y dónde Si nada cambió, estos pasos se saltan por completo, así que no necesariamente se ejecutan cada fotograma. Solo el paso final de composición, que toma la salida producida y la ensambla en pantalla, se delega al hilo compositor.

En otras palabras, la mayor parte de la primera mitad del canal que dibuja la pantalla es responsabilidad del hilo principal. El canal de renderizado para actualizar la pantalla Para que la pantalla se vea suave, los fotogramas tienen que dibujarse a la tasa de refresco del display. En el display de 60Hz más común, eso significa 60 fotogramas por segundo, o unos 16,6 milisegundos por fotograma.

Y no puedes usarlo todo. Una vez restado el coste de procesamiento propio del navegador, el presupuesto práctico suele considerarse alrededor de 10 milisegundos, y en un dispositivo de 120Hz el presupuesto en sí se reduce a la mitad. El problema es que los dos tipos de trabajo anteriores están en una sola fila en el mismo hilo.

JavaScript fue diseñado en torno a un modelo de bucle de eventos de un solo hilo. El hilo principal procesa una tarea a la vez, y mientras esa tarea se está ejecutando, no puede pasar nada más. Si una función de JavaScript se ejecuta durante 200 milisegundos, entonces durante esos 200 milisegundos el navegador no puede repintar la pantalla ni recibir un clic del usuario.

Frente a un presupuesto de fotograma de unos 10 milisegundos, esa es una cantidad de tiempo fatal. Una tarea que ru...