Mejora de 30 veces el uso de la memoria del front-end en la carga del carrusel

En el segundo trimestre de 2020, llevamos a cabo una refactorización técnica de la página de experiencias, reescribiéndola en React y utilizando la API REST. Sin embargo, durante la implementación, nos encontramos con un problema interesante.
Hay alrededor de 20 carruseles en la página de experiencias, cada uno con al menos 60 mosaicos. Por lo tanto, la página mostrará más de 1200 experiencias, incluyendo información relevante como su título, valoración de los usuarios, usuarios simultáneos y miniatura. En cada carrusel, al hacer clic en el botón de desplazamiento hacia la derecha se envía una solicitud para cargar el siguiente lote de experiencias si hay más. A continuación, los nuevos datos resultantes de la solicitud se añadirán al carrusel, lo que significa que se añadirán más nodos al DOM y se renderizarán más miniaturas en el navegador. El uso de memoria dentro del navegador aumentará a medida que los usuarios se desplacen para solicitar más datos, y entonces la experiencia de usuario se ralentizará y comenzará a sufrir retrasos.

Perfil de memoria
Podemos utilizar las Herramientas para desarrolladores de Chrome para analizar este problema. La primera captura se toma cuando la página se carga inicialmente, y la segunda se toma después de que el usuario haya hecho clic 12 veces en el botón de desplazamiento siguiente de un carrusel. Observamos un aumento de casi 9,7 MB en el uso de memoria debido a más de 100 nodos de cadena y a un mayor renderizado de miniaturas.

Solución
Cuando el carrusel se desplaza, los usuarios solo ven los elementos de la ventana del carrusel. Por ejemplo, en un portátil con una resolución de 1920×1080, en el navegador a pantalla completa, solo habrá unos 9 elementos visibles cada vez. Por lo tanto, no es necesario renderizar todos los nodos y miniaturas invisibles a la vez ni incorporar al DOM más datos devueltos por la solicitud.
Así pues, esta es la idea: después de obtener los datos sin procesar de la solicitud de la API por primera vez, creamos una matriz de la misma longitud para prepararnos para la representación en el DOM. Dentro de la matriz de representación, podemos rellenar solo los datos suficientes para llenar la pantalla y pasar a la siguiente. El resto de la matriz se rellenará solo cuando la ventana de visualización se desplace hasta cerca de ella. Asignemos dos índices para registrar el rango de los datos de renderizado: renderingStartIndex y renderingEndIndex. Configuramos un cursor para indicar qué posición inicial de la lista es visible. Al desplazarnos, debemos actualizar continuamente el cursor al índice del primer elemento visible. Antes de que finalice la animación de desplazamiento, tendremos que comprobar si el cursor siguiente se encuentra dentro de la matriz de datos de renderizado. Según el tamaño de la ventana del carrusel y el tamaño de las tarjetas, podemos determinar fácilmente cuántos elementos visibles cabrán en la ventana de visualización. A continuación, debemos asegurarnos de que los elementos de la ventana actual y de la siguiente ventana se encuentren dentro del rango de la matriz de datos de renderizado. Si no es así, tomamos elementos de los datos sin procesar para rellenar la lista vacía, al tiempo que borramos los datos anteriores a la posición del cursor. Esto se aplicará cuando los usuarios se desplacen hacia la derecha o hacia la izquierda. Cuando los usuarios se desplazan hacia la derecha, al recuperar más datos en segundo plano, rellenaremos los datos sin procesar cada vez que recibamos nuevos datos. Sin embargo, los datos sin procesar no se incluirán en la representación de la página.


Perfil de memoria
Echemos un vistazo de nuevo a las Herramientas de desarrollador de Chrome. Al igual que antes, la primera captura se realiza en el momento de la inicialización y la segunda, tras desplazarse hacia la derecha 12 veces. Ahora, cargar más de 100 elementos solo supone un aumento de 0,3 MB de memoria, frente a los 9,7 MB anteriores.

¿Qué viene ahora?
Además de mejorar el componente carrusel para gestionar ventanas de datos de gran tamaño, cuando refactoricemos una función o página, debemos añadir más pruebas de rendimiento para recopilar la información de rendimiento.
Aunque la pila de aplicaciones web modernas se ha ido desplazando hacia el front-end, capturar y mejorar la telemetría del front-end es tan importante como la telemetría tradicional del back-end.
Ying Jiang es ingeniera principal de software front-end en Roblox. Como primera ingeniera front-end de Roblox, trabaja para introducir una pila tecnológica front-end moderna en Roblox y mejorar el proceso de desarrollo e implementación. También ha trabajado en funciones en tiempo real como el chat, el flujo de notificaciones y la voz.
Ni Roblox Corporation ni este blog respaldan ni apoyan a ninguna empresa o servicio. Además, no se ofrecen garantías ni promesas respecto a la exactitud, fiabilidad o exhaustividad de la información contenida en este blog.


