A pesar del crecimiento del rendimiento del dispositivo, la web se está volviendo cada vez más exigente en cuanto a memoria y procesador. La representación adecuada y la asignación inteligente de recursos en las pestañas es una parte importante para resolver este problema. Konstantin Kramlih
PurplePowder dedicó su discurso en la
conferencia "I Frontend" a algoritmos que mejoran la productividad y ahorran recursos tanto en el proyecto Chromium como en Yandex.Browser.
Algunos de ellos, por ejemplo, la tecnología Hibernate, ya los hemos clasificado en una
publicación separada . El informe Bones cubre el problema de manera más amplia: no solo desde el punto de vista del cambio de pestañas, sino también teniendo en cuenta los métodos de representación de contenido, mosaicos y capas de página.
Al final, los desarrolladores de interfaces web pueden aprender a identificar y resolver problemas de rendimiento del sitio web.
- Mi nombre es Kostya, soy el jefe del grupo de desarrollo de componentes internos en el equipo Yandex.Browser. En el navegador, he estado haciendo cosas diferentes durante un poco más de cinco años: desde la decodificación en el navegador, desde todos los videos HTML5, hasta el renderizado, renderizado y otros procesos similares.
Durante el último año y medio o dos, he estado involucrado en proyectos relacionados con el ahorro de recursos en el navegador: CPU, memoria, batería.
Usted dice: Kostya, en el patio en 2019, ¿dónde están los problemas con los recursos? Puede comprar cualquier dispositivo que desee con cualquier recurso. Pero si pasamos a las estadísticas abiertas de Mozilla, veremos que la mitad de los usuarios tienen 4 GB de memoria o menos. Y muchos usuarios que tienen uno o dos núcleos físicos, constituyen una proporción considerable de su audiencia. En este mundo vivimos.

¿Cuántos de ustedes ven a menudo esta pestaña? Esto es exactamente lo que sucede en el caso de usuarios comunes que tienen poca RAM y computadoras viejas.

Que hacer El problema no es secreto para nadie, comenzaron a luchar activamente con él hace unos tres años. Desde entonces, las tuercas se han apretado gradualmente de varias maneras. Permíteme mostrarte un ejemplo que fue sobre Stack Overflow alrededor de 2016. Aquí hay un fragmento bastante simple. Esto simplemente actualiza el título y establece el tiempo transcurrido desde el último lanzamiento de esta función. ¿Qué se debe obtener idealmente? Cada 100 ms en el título debe escribirse + -100. Que suerte

Pero, ¿y si abrimos y hacemos esto? ¿Alguien se ha topado con esto? La pregunta fue para Stack Overflow: ¿qué demonios deja de hacer clic Cookie Cookie en mis pestañas de fondo? Esta fue una de las primeras iniciativas de Chromium destinadas a reducir el uso de CPU en el navegador. La idea era que si el usuario no usa la pestaña ahora, entonces no la necesita ahora, pongamos JS en ella.
El navegador intenta mantener la carga de la CPU en esta pestaña en aproximadamente el 1%; comienza a pausar todo tipo de temporizadores, ejecución de JS, etc. Este es uno de los primeros pasos en el futuro brillante.

Después de un tiempo en el navegador, verá que las pestañas de fondo dejan de funcionar. Este es el brillante futuro del que estoy hablando. De acuerdo con los planes de Chromium, que expresaron en el último BlinkOn, en 2020 planean hacerlo: dejar que se cargue la pestaña y, si está en segundo plano, no hará nada. Siempre debes estar preparado para esto.

En Yandex.Browser, también nos ocupamos de ese problema, pero lo resolvimos de manera menos categórica y no rompimos toda la web. Creamos un modo de ahorro de energía que desactiva la decodificación en el procesador y deja solo la decodificación en la tarjeta de video, y también reduce el FPS y desactiva algunas animaciones que no se necesitan en este momento y en lugar de las cuales el usuario debería ahorrar batería. Esto nos dio aproximadamente una hora de duración adicional de la batería. Cualquiera puede verificar, ixbt, por ejemplo,
verificado .

Creo que algunos dirán: Kostya, "rompiste" la web, ayudaste a algunos usuarios, pero no se te ocurrió nada más inteligente. Añadir hardcore! ¿Cómo dibujan las páginas los navegadores?

El concepto de capas, en pocas palabras, es cuando el navegador intenta dividir la página en capas y dibujarlas por separado. Esto se hace para que se realicen algunas animaciones y no se obligue a volver a dibujar lo que es estático. El navegador hace esto en diferentes heurísticas. Por ejemplo, tratar de seleccionar un elemento de video en una capa separada, que, obviamente, se vuelve a dibujar rápidamente y con frecuencia. Y si se muestra en algún lugar, entonces no es necesario volver a dibujar todo debajo.
Además, cada capa se divide en dichos mosaicos: 256 por 256 rectángulos. En el inspector puede ver algo como esto. Hay un marco que se divide en un montón de fichas.


¿Qué es y por qué se necesita? En primer lugar, priorizar el renderizado. Si tenemos una salchicha enorme, en la que todos dibujamos, ¿por qué necesitamos dibujar todo esto si ahora el usuario solo ve lo que tiene ahora en ViewPort?

Con este enfoque, primero dibujamos solo lo que el usuario ve en este momento en ViewPort, luego un mosaico alrededor, luego en la dirección del desplazamiento. Si el usuario se desplaza hacia abajo, dibuje hacia abajo, si está hacia arriba. Todo lo demás se dibujará solo si tenemos una cuota para estos mosaicos y podemos dibujarlos, después de lo cual el usuario los verá alguna vez. O tal vez nunca.

También ayuda mucho con discapacidades. Supongamos que un usuario abre una página, selecciona una pieza y no necesitamos volver a dibujar todo. Podemos dejar la mayor parte del renderizado anterior. Redibujaremos seis mosaicos aquí, y todo estará bien.

Justo en este nivel, se realizaron varias optimizaciones muy exitosas. Por ejemplo, Chromium realizó tal optimización alrededor de 2017.

Si solo tenemos una pequeña representación, solo lo hacemos. Luego, el cursor parpadea y redibujamos solo el área del cursor, pero no toda el área de este mosaico. Ahorramos mucho CPU para no volver a dibujar todo.

También ayuda a ahorrar memoria. ¿Cuál es el problema aquí? Rectángulos blancos enteros. Imagine que sería una textura de 256 por 256, cuatro bytes por píxel. Aunque parece que esta área se puede codificar con solo cinco números: coordenadas, ancho, alto y color.

En Chromium, se ha optimizado las áreas monocromas. Si el navegador entiende que no hay renderizado en este rectángulo, que es completamente monocromático, no transparente y cumple con otras condiciones, entonces simplemente le decimos a la tarjeta de video: dibuje un rectángulo blanco, no seleccione toda la textura.
¿Qué más se puede optimizar aquí? Si nos fijamos en los mosaicos restantes, tienen poco contenido y una gran área de color blanco. En Yandex.Browser, pensamos en esto e hicimos un mecanismo que llamamos mosaico adaptativo.

Hay un pequeño rectángulo, un azulejo. Hay poco contenido en el medio del mosaico. Lo seleccionamos y, solo debajo, la textura. Todo lo demás también se divide en varias áreas, de las que estamos hablando de la tarjeta de video: solo dibuje en blanco aquí este tamaño.

La página también comienza a guardar todo lo que está resaltado en rojo. En páginas más complejas, se ve más o menos así.

Es importante entender que todavía hay un montón de capas y cada capa se dibuja así. En cada capa, puede guardar cierta cantidad de memoria. Este enfoque nos permitió ahorrar aproximadamente el 40% de la memoria de video en promedio para todos los usuarios.
Más hardcore! Ahorraron un poco de memoria aquí, "rompieron" la web. ¿Por qué no "rompen" la web aún más?
En Chromium hay algo así como una política: si el usuario no usa pestañas de fondo, si las dejó, entonces no las necesita. Si ahora no tenemos memoria y el navegador ahora se acostará, tomemos la pestaña más antigua que el usuario no haya usado durante mucho tiempo y elimínela. Ella permanecerá en la interfaz, pero el proceso ya no estará allí, todos los JS morirán. ¿Está bien o no está bien? Es extraño hacer una pregunta así en la fiesta de front-end y esperar cualquier respuesta que no sea "¿Qué estás haciendo?"

Entonces no fue mucho. Aquí están los comentarios reales del blog de Chromium: rompiste todas mis aplicaciones para mí, había algún tipo de juego, y salta, no tiene estado. Es importante entender que allí el controlador de descarga no funcionó, como si simplemente hubiéramos publicado esta pestaña. Luego, el usuario vuelve a él y lo volvemos a cargar desde la red, como si nada hubiera pasado.
Luego, este enfoque se abandonó temporalmente y se le ocurrió una idea seria más reflexiva. La llamaron descarte.

Cual es el punto? Esta es la misma eliminación de pestañas, solo controlada. Se llama la palabra inteligente
Page Lifecycle API . Si tiene una pestaña y el usuario no la ha visto durante mucho tiempo, puede pasar al estado congelado. El navegador dice durante el evento: voy a congelarte ahora. Después de procesar el evento, no se realizará nada en absoluto. Haz lo que necesites, prepárate.
Luego puede salir del estado congelado a través del evento de reanudación, supuestamente no sucedió nada. O, si el navegador realmente necesita liberar memoria en este momento, simplemente lo toma y lo mata. Pero si el usuario vuelve a esta pestaña, la volveremos a cargar y configuraremos el campo descartado para el documento.

En este momento ya puedes suscribirte a estos eventos y atraparlos, de alguna manera procesarlos. Si la pestaña se elimina realmente, puede verificar que el campo se descartó. Esto significa que ha sido restaurado después de un descarte. Puede restaurar el estado anterior.

Nosotros en Yandex.Browser pensamos hace unos años: ¿por qué no usar un enfoque cardinal complejo? Lo llamaron Hibernate.

Cual es el punto? Hay varias pestañas, se está ejecutando algún tipo de JS, algún tipo de estado. Se crea un proceso separado para cada pestaña: aquí se puede reproducir un video, aquí se deja algo en el formulario. Hibernate llega, y no hay procesos. Todos los tenemos. Pero si ahora volvemos a estas pestañas, el proceso volverá y todo el estado estará en su lugar, el video continuará reproduciéndose en el momento correcto, todo el texto en los campos permanecerá en su lugar.

Que hemos hecho Las tres cosas más importantes viven dentro de cada renderizador: V8, que ejecuta todo el JS, Blink, que almacena todo el DOM, y algún tipo de enlace de navegador que ayuda a conectar todo, con pestañas y todo lo demás.

Por ejemplo, considere una muestra. Aquí esperamos que ocurra la carga y agregamos un nuevo elemento div al árbol DOM. Para el navegador, se ve más o menos así.

Naturalmente, hay un árbol DOM, tiene algunos campos, objetos asociados y existe dicha entidad.

En V8, el estado de cada nodo se almacena, y estos nodos están asociados con objetos parpadeantes a través de una capa de carpetas. Que hemos hecho Tomamos el serializador de V8, serializamos todo el estado de V8, encontramos todos los objetos relacionados en Blink, escribimos más serializadores que guardan todo el árbol DOM, serializan, luego escriben en el disco, comprimen y encriptan. Y le enseñamos al navegador a recuperarse de esa instantánea. Es decir, cuando el usuario accede a dicha pestaña, la expandimos, la desciframos y se la mostramos al usuario, la restauramos por completo. (
Una publicación separada sobre Hibernate - aprox. Ed.)
En este momento, Hibernate se publica para todos en estable y permite a cada usuario guardar un promedio de una o dos pestañas. Es decir, tiene en promedio una pestaña siempre guardada, o tal vez dos. Esto ahorra memoria para los usuarios que tienen más de 10 pestañas, como hacemos con usted, pero no somos representativos.
Le dije cómo el navegador está tratando de ayudar, pero ahora cada uno de ustedes puede hacer algo para acelerar el sitio, mejorar su rendimiento. Puedes venir y hacer lo correcto hoy.
Primero debe comprender si hay problemas de memoria.

Hay ciertos síntomas: el sitio comienza a degradarse o aparece desvanecimiento. Por lo general, esto significa que se activa el recolector de basura, todo el mundo está congelado y no se está dibujando nada. O que el sitio simplemente se ralentiza constantemente, como también sucede.
Necesita comprender si hay un problema. Observamos lo que sucede con la memoria JS.

Si salta hacia adelante y hacia atrás o crece continuamente, este no es un buen síntoma. O creciendo continuamente.

En este caso, siempre puede tomar una instantánea a través de DevTools. ¿Alguien se ha molestado con fugas en JS? Si alguien no sabe, en JS es muy posible hacer una fuga.

Por ejemplo, tiene una variable global donde agrega nodos que no se insertan en el árbol. Te olvidas de ellos, y luego resulta que están comiendo cientos de kilobytes, o incluso megabytes.

Estrictamente hablando, no está claro qué hacer con estos nodos separados. Puede sacarlos del árbol y luego volver a insertarlos. Porque generalmente el estado de la imagen o algo más permanece con ellos. Por lo tanto, puede encontrarlos y tratar el problema.

También puede ver la asignación de memoria en la línea de tiempo. Si tiene una descarga sistemática y nunca se limpia, esto también es una mala señal, creo que todos lo entienden.

Y puedes jugar con las capas en tu pestaña. El navegador generalmente trabaja con heurística en este sentido: trata de separar los objetos que considera que cambian con frecuencia en capas separadas. Pero a veces no funciona muy bien, y resulta que tiene muchas capas que consumen mucha memoria. Siempre puede ver si tiene una situación así, eliminar algunas capas y descubrir cuánta memoria ocupa esta capa.

Otra capa de problemas es el rendimiento. setTimeout es una mala idea para la animación. No funciona de la forma en que el navegador quiere representar la página. Es posible que no funcione en fase: el navegador solicitó un marco, pero aún no hay animación, porque setTimeout no funcionó. O puede funcionar incluso cuando no necesite dibujar nada. El usuario se fue, todavía queda algo de trabajo de fondo, pero trabajaremos con él a través de setTimeout.
Este es el enfoque correcto que su devolución de llamada llamará solo cuando el navegador necesite dibujar esta página.

También quiero recordarle que si el navegador quiere dibujar 60 cuadros por segundo, significa que para cada cuadro necesita unos 16 ms.

Y si ocupa la transmisión principal durante más de 16 ms, entonces tiene un salto de trama garantizado, lo cual es bastante desagradable para el usuario: el sitio comienza a sacudirse. Por lo tanto, todo el trabajo duro se coloca correctamente en los hilos de fondo, que simplemente devuelve el resultado.

O otro enfoque es utilizar microtasking. Cree una cola de tareas, procese después de un tiempo, hasta que termine la cuota, y deje que el navegador dibuje la página con calma.

Naturalmente, puede agregar nuevas capas. El navegador funciona con heurística e intenta seleccionar la capa donde lo considera necesario. Pero si sabe que en este momento este elemento estará animado, es mejor decirle al navegador explícitamente que necesita seleccionar este elemento en una capa separada. Entonces se dibujará de manera más eficiente.

El último enfoque interesante: quejarse. Si tienes problemas, siempre es útil venir y hablar. Quizás este problema pueda tratarse fácilmente y nos ayudaremos mutuamente.
Un poco de historia. Esta característica se está trabajando actualmente. Tenemos un equipo de página de desarrollo de motores de búsqueda. Tienen una métrica como el momento de renderizar el primer fragmento. Si el usuario ve previamente el primer enlace en el que debe hacer clic y que probablemente le dé la respuesta correcta, entonces es mucho mejor dibujarlo lo más rápido posible. Vinieron y preguntaron si era posible acelerar de alguna manera esta vez, porque todos se habían exprimido.
Investigamos, realizamos pruebas de rendimiento, hicimos un prototipo y resultó que podemos hacerlo si el sitio nos dice qué dibujar primero. Probamos y vemos que mejora nuestro rendimiento. Ahora estamos probando esto en producción para un público reducido. Miramos lo que saldrá de eso. Estén atentos.
El mundo no se detiene. El usuario comienza a querer más y más, los navegadores están cambiando, la web está cambiando. Esto es normal Intentamos no solo crear funciones de supermercado, sino también ayudar al usuario de todas las formas posibles a obtener la mejor experiencia en términos de consumo de contenido. Y siempre debe estar preparado para los cambios en cualquier navegador popular. Naturalmente, si hay problemas, venga, estamos listos para discutir y ayudarnos mutuamente.
Aquí reuní varios enlaces útiles: