Réduire de 30 fois l'utilisation de la mémoire frontale lors du chargement du carrousel

Au deuxième trimestre 2020, nous avons procédé à une refonte technique de la page « Expériences », en la réécrivant en React et en utilisant l'API REST. Mais lors de la mise en œuvre, nous avons rencontré un problème intéressant.
La page « Expériences » comporte environ 20 carrousels, chacun contenant au moins 60 vignettes. La page affiche donc plus de 1 200 expériences, avec des informations pertinentes telles que leur titre, la note des utilisateurs, le nombre d'utilisateurs simultanés et une vignette. Dans chaque carrousel, cliquer sur la flèche de défilement vers la droite envoie une requête pour charger le lot suivant d'expériences s'il y en a d'autres. Les nouvelles données issues de cette requête seront alors ajoutées au carrousel, ce qui signifie que davantage de nœuds seront ajoutés au DOM et que davantage de vignettes s'afficheront dans le navigateur. L'utilisation de la mémoire au sein du navigateur augmentera à mesure que les utilisateurs feront défiler la page pour demander davantage de données, ce qui ralentira l'expérience utilisateur et entraînera des ralentissements.

Profil de mémoire
Nous pouvons utiliser les outils de développement de Chrome pour analyser ce problème. Le premier instantané est pris lors du chargement initial de la page, et le second après que l'utilisateur a cliqué 12 fois sur le bouton de défilement suivant dans un carrousel. Nous constatons une augmentation de près de 9,7 Mo de l'utilisation de la mémoire due à plus de 100 nœuds de chaîne et à un rendu accru des vignettes.

Solution
Lorsque le carrousel défile, les utilisateurs ne voient que les éléments affichés dans la fenêtre du carrousel. Par exemple, sur un ordinateur portable avec une résolution de 1920×1080, en mode plein écran, seuls environ 9 éléments seront visibles à chaque fois. Il n’est donc pas nécessaire de rendre tous les nœuds et vignettes invisibles en même temps, ni d’intégrer dans le DOM davantage de données renvoyées par la requête.
Voici donc l'idée : après avoir récupéré les données brutes de la requête API pour la première fois, nous construisons un tableau de même longueur en vue de l'affichage dans le DOM. À l'intérieur de ce tableau d'affichage, nous ne remplissons que les données nécessaires pour remplir l'écran et passer à la page suivante. Le reste du tableau ne sera rempli que lorsque la fenêtre d'affichage se rapprochera de cette zone. Attribuons deux indices pour enregistrer la plage des données de rendu : renderingStartIndex et renderingEndIndex. Nous configurons un curseur pour indiquer quelle position de départ dans la liste est visible. Lors du défilement, nous devons continuellement mettre à jour le curseur à l’index du premier élément visible. Avant que l’animation de défilement ne soit terminée, nous devrons vérifier si le curseur suivant se trouve à l’intérieur du tableau de données de rendu. En fonction de la taille de la fenêtre du carrousel et de la taille des cartes, nous pouvons facilement déterminer combien d’éléments visibles tiendront dans la fenêtre d’affichage. Ensuite, nous devons nous assurer que les éléments de la fenêtre actuelle et de la fenêtre suivante se trouvent dans la plage du tableau de données de rendu. Si ce n’est pas le cas, nous récupérons des éléments à partir des données brutes pour remplir la liste vide tout en effaçant les données situées avant la position du curseur. Cela s’applique lorsque les utilisateurs font défiler vers la droite ou vers la gauche. Lorsque les utilisateurs font défiler vers la droite, en récupérant davantage de données en arrière-plan, nous remplissons les données brutes à chaque fois que nous recevons de nouvelles données. Cependant, les données brutes ne seront pas prises en compte dans le rendu de la page.


Profil de mémoire
Revenons aux outils de développement de Chrome. Comme précédemment, le premier instantané est pris au moment de l'initialisation et le second après avoir fait défiler la page vers la droite 12 fois. Désormais, le chargement de plus de 100 éléments n'entraîne qu'une augmentation de 0,3 Mo de mémoire, contre 9,7 Mo auparavant.

Et ensuite ?
Outre l'amélioration du composant carrousel pour gérer les fenêtres de données volumineuses, lorsque nous refactorisons une fonctionnalité ou une page, nous devons ajouter davantage de benchmarks pour recueillir les informations de performance.
Alors que la pile des applications web modernes s'est déplacée vers le front-end, la collecte et l'amélioration des données télémétriques du front-end sont tout aussi importantes que celles du back-end traditionnel.
Ying Jiang est ingénieure logicielle front-end principale chez Roblox. En tant que première ingénieure front-end de Roblox, elle s'efforce d'introduire une pile technologique front-end moderne au sein de l'entreprise et d'améliorer le pipeline de développement et de déploiement. Elle a également travaillé sur des fonctionnalités en temps réel telles que le chat, le flux de notifications et la voix.
Ni Roblox Corporation ni ce blog ne cautionnent ou ne soutiennent aucune entreprise ou service. De plus, aucune garantie ni promesse n'est donnée quant à l'exactitude, la fiabilité ou l'exhaustivité des informations contenues dans ce blog.


