Solucionando Problemas de Rendimiento en React

Rate this content
Bookmark

Next.js y otros marcos de trabajo que envuelven a React proporcionan un gran poder en la construcción de aplicaciones más grandes. Pero con gran poder viene una gran responsabilidad de rendimiento - y si no prestas atención, es fácil añadir varios segundos de penalización de carga en todas tus páginas. ¡Vaya! Vamos a recorrer un estudio de caso de cómo unas pocas horas de depuración de rendimiento mejoraron tanto los tiempos de carga como los de análisis para la aplicación Centered en varios cientos por ciento cada uno. Aprenderemos no solo por qué ocurren esos problemas de rendimiento, sino cómo diagnosticarlos y solucionarlos. ¡Viva el rendimiento! ⚡️

Josh Goldberg
Josh Goldberg
22 min
23 Oct, 2023

Video Summary and Transcription

Esta charla discute varias estrategias para mejorar el rendimiento de React, incluyendo la carga perezosa de iframes, analizando y optimizando paquetes, arreglando las exportaciones de barril y el tree shaking, eliminando código muerto, y almacenando en caché cálculos costosos. El orador comparte su experiencia en la identificación y solución de problemas de rendimiento en una aplicación del mundo real. También destacan la importancia de auditar regularmente webpack y los analizadores de paquetes, utilizando herramientas como Knip para encontrar código no utilizado, y contribuyendo con mejoras a las bibliotecas de código abierto.

Available in English

1. Introducción al Rendimiento de React

Short description:

Hola, y bienvenidos a Power Fixing React Performance Woos. El rendimiento web es increíble. Los marcos modernos como SvelteKit, Nuxt, Next, Remix y Nastro son buenas opciones para el rendimiento. Voy a guiarte a través de una serie de cinco mejoras que hice en el popular sitio web center.app. La primera mejora es abordar los 81 incrustaciones de iframe.

Hola, y bienvenidos a Power Fixing React Performance Woos, conmigo, Josh Goldberg. Soy un mantenedor de código abierto. Trabajo en el ecosistema de TypeScript y escribí un libro, Aprendiendo TypeScript, publicado por O'Reilly, pero no estamos aquí para hablar de todo eso.

Estamos aquí para hablar sobre el rendimiento web, sobre cómo solucionar cosas. El rendimiento web es increíble. Si no estás convencido, te recomiendo encarecidamente web.dev. ¿Por qué importa la velocidad? Resumiendo sus puntos, la velocidad es importante para retener a tus usuarios, es más probable que se queden. Mejorar las conversiones, eso es bueno para el dinero. No es bueno para tu experiencia de usuario porque a la gente no le gustan las páginas web lentas, hecho divertido. Es un punto de accesibilidad porque las personas con hardware limitado y/o ancho de banda a menudo no pueden usar o tienen problemas para usar páginas web realmente pesadas y lentas. No lo queremos.

Los frameworks modernos como SvelteKit, Nuxt, Next, Remix y Nastro y todos estos hacen muchas buenas elecciones por ti. Así que si estás usando algo como, digamos, NextJS, que veremos más tarde, a menudo está configurado para hacer del buen rendimiento la opción predeterminada, lo que en realidad hace más difícil escribir páginas web lentas. Pero no es imposible. No te impiden introducir agresiones de rendimiento. Incluso si estás haciendo todo bien, todavía es posible que con el tiempo se vayan colando cosas. Voy a guiarte a través de una serie de cinco mejoras que hice, solo algunas de las cuales tocan realmente el código de React en el popular sitio web center.app.

Ahora, esto es de un equipo perfectamente bueno y respetable. No hicieron nada mal, excepto que simplemente no tuvieron tiempo para centrarse en el rendimiento, lo que significó que algunos problemas de rendimiento se colaron en la aplicación, con los que pude ayudar. Normalmente, cuando abordo un problema de rendimiento, es en cuatro fases. Identificación, ver qué está mal, idealmente con algo que pueda medir. Investigación, buscar cuál es la causa raíz. Implementación, idealmente de una solución. Y confirmación de que la solución realmente solucionó lo que queríamos.

La primera de estas es una muy rápida, 81 incrustaciones de iframe. He visto esto muy raramente, así que fue realmente genial encontrarlo aquí. Cuando miras la página de center.apps slash quotes, antes de las correcciones, tardaría una eternidad. Mira lo lenta que era. Y la causa raíz era, veremos pronto, que tenía muchos iframes. Pero el efecto, el síntoma, era que tardaba una eternidad y se sentía lenta.

2. Identificando el Problema con los Iframes

Short description:

Y tenía una pista porque había visto muchos tweets aparecer en una página y tardar un rato antes. Así que simplemente mirando a través de las herramientas de desarrollo, vemos una grabación aquí de mí confirmando que, sí, es lo que sospechaba que hay muchos iframes en esta página. Y hecho divertido sobre los iframes. Podemos ver aquí que hay bastantes de ellos.

Y tenía una pista porque había visto muchos tweets aparecer en una página y tardar un rato antes. Así que simplemente mirando a través de las herramientas de desarrollo, vemos una grabación aquí de mí confirmando que, sí, es lo que sospechaba que hay muchos iframes en esta página. Y hecho divertido sobre los iframes. Podemos ver aquí que hay bastantes de ellos. Cada iframe es como una página dentro de una página. Así que cuando tienes 84 de ellos o 81 de ellos, eso es bastante páginas. Cuando se tomó esta grabación ayer, en realidad había más iframes de los que había inicialmente hecho la investigación. Fue un total de 94. Así que eso es bastante la desaceleración. Y todos aparecen al mismo tiempo, lo que significa que todos se están cargando al mismo tiempo, por lo que la página se congeló y tardó un rato en cargar. Boom.

3. Solucionando la Representación de Iframes con Carga Diferida

Short description:

Al implementar una solución para la representación de múltiples iframes, se utilizó la carga diferida. Inicialmente solo se representa un subconjunto de los iframes, y se cargan más a medida que el usuario interactúa con la página. La carga diferida mejoró el rendimiento al reducir el tiempo de carga inicial. Este enfoque no es específico de React y se puede aplicar a otros proyectos de desarrollo web. Es importante optimizar las aplicaciones para el rendimiento, incluso si inicialmente estaban bien elaboradas. La carga diferida es una estrategia recomendada para la representación de grandes cantidades de contenido, especialmente cuando solo una parte de este es inicialmente visible para los usuarios.

Al implementar una solución, primero encontré donde se representan los iframes, que es este componente de tarjetas de uso general. Aquí está simplificado, pero en esencia, carga los datos de la tarjeta usando un hook, y luego para cada pieza de esos data, almacenada en un array, se mapearía en este componente de tarjeta, representándolo como un componente hijo. Y ese componente de tarjeta llama a React Twitter Embed, que es un paquete NPM popular perfectamente bueno que incrusta un tweet como un iframe.

Esa es la forma estándar de usar las características de incrustación de tweets externos de Twitter, especialmente desde que se volvieron solo privados o solo de costo para sus APIs. Entonces, grandes números, docenas, casi 100 iframes todos representándose a la vez. La estrategia que a menudo tomaría en una situación como esta es la carga diferida. Esta es una simplificación de la solución que implementamos con carga diferida. Primero, hacemos un dot-slice a las tarjetas, de modo que solo la tarjeta 0 hasta, en este caso comenzando en 6, se representan a la vez. Luego, cada vez que se carga una tarjeta, al cargar, incrementamos o agregamos un poco a un contador extra, diciendo que podemos cargar adicionalmente esta cantidad de tarjetas. Entonces, después de que se cargan las primeras tarjetas, podemos seguir cargando más y más.

Ahora, 6 es un número arbitrario, pero funcionó bien aquí porque ese es aproximadamente el número máximo de iframes que alguien vería al cargar la página por primera vez. En teoría podríamos haberlo basado en el viewport de la página o algo así, pero no tuve tiempo, solo estaba haciendo esto por diversión. Y, solo para confirmar, mucho más rápido para grabar. Todavía está cargando la misma cantidad de iframes, solo está esperando para cargar. Está siendo perezoso al cargar todos menos los primeros 6. Entonces, yay, eso se sintió bien. Y como veremos en las cuatro investigaciones restantes, no hay mucho material específico de React aquí. Pero, son buenos principios web generales. Entonces, algunas conclusiones. Uno, las aplicaciones no optimizadas son, en mi experiencia, las más divertidas de investigar porque podrían estar totalmente bien elaboradas, simplemente no han tenido tiempo de hacer esas frutas bajas, esas victorias mucho más sencillas para el performance. Dos, este código probablemente estaba totalmente bien cuando se escribió por primera vez. Imagino que cuando se implementó la página por primera vez probablemente solo tenía 6 o 12 citas como máximo, no es ideal pero no está en ninguna parte cerca de casi 100 iframes. Y por último, la carga diferida es increíble, muy recomendada como estrategia. Si tienes un montón de cosas que quieres mostrar y solo algunas de ellas son inicialmente visibles para los usuarios, tal vez esperes para representar el resto de ellas hasta un segundo o dos. Sigamos adelante.

Imágenes incrustadas ocultas. Esto fue divertido. Entonces, hice una puntuación de performance, que es la estándar de DevTools, hey, ¿cómo está el performance? dentro de la familia general de verificaciones de Lighthouse para una página. Y vino con una puntuación de 36, que no es ideal, está en rojo. Y bajando las oportunidades sugeridas para crecer, que recomendaría encarecidamente investigar si alguna vez obtienes una puntuación de performance en rojo o amarillo, la que primero me llamó la atención fue, tamaño total 26 mil y medio kib, o aproximadamente dos docenas de megabytes.

4. Analizando los Paquetes e Identificando el Problema

Short description:

Vaya, eso es mucho código cargado por la página. Utilicé el Analizador de Paquetes de Webpack para analizar los paquetes y fragmentos de JavaScript en la aplicación. Esto me ayudó a identificar el problema con el archivo illustration.js de las características de Gcal, que era la mayor parte de cualquier fragmento por un orden de magnitud. Contenía imágenes codificadas en base64 y código no utilizado.

Vaya, eso es mucho código, eso es mucha información enviada a través de la red. ¿Por qué se estaba cargando tanta información? ¿Por qué la página estaba cargando tanta información? Bueno, abrí esta gran herramienta llamada el Analizador de Paquetes de Webpack. Como la Aplicación Centralizada está escrita en Next.js, pudimos usar la muy sencilla integración de Next.js con el Analizador de Paquetes, lo que hizo relativamente sencillo abrir el require Next slash Bundle Analyzer y ejecutarlo si el proceso y analizar es verdadero. En otras palabras, seguí las instrucciones y luego ejecuté este comando, MPM run build. Esto creó una versión de producción local de la aplicación analizando los paquetes o los fragmentos generados de JavaScript.

5. Analizando el Problema con las Características de Gcal

Short description:

Y mi parte favorita de la herramienta es que viene con una bonita visualización. illustration.js de las características de Gcal era lo más grande en la página, convirtiendo el fragmento de la aplicación en una monstruosidad de nueve megabytes. El archivo contenía imágenes codificadas en base64, lo cual no es ideal para el rendimiento. Eliminé el archivo, lo que resultó en un fragmento de página mucho mejorado y una disminución en la Pintura de Contenido más Grande de 17.6 segundos a 13.2 segundos.

Y mi parte favorita de la herramienta es que viene con una bonita visualización. Y esta visualización mostró que illustration.js de las características de Gcal era, con diferencia, lo más grande en la página, la parte más grande de cualquier fragmento por un orden de magnitud, varios megabytes. Convirtió el fragmento más grande y más importante, el fragmento de la aplicación, en una monstruosidad de nueve megabytes. Enorme. Nunca había visto algo tan grande en algo revisado en el repositorio. Me encanta.

Esto me parece realmente genial. Así que miré el archivo y vi que tenía un montón de imágenes incrustadas como base64. Ahora, base64 es una forma de codificar una imagen o algún trozo de data como una cadena. Y es totalmente razonable usarlo para imágenes pequeñas. Pero si tienes una que codifica a millones de caracteres, si es una imagen de varios megabytes, codificarla en base64 en tus SVGs dentro de tus componentes de React generalmente no es una buena idea para el performance. Podría haber sido una forma rápida y agradable de prototipar una característica. Pero esto no es bueno para la producción porque requiere que el usuario descargue y cargue megabytes tras megabytes de JavaScript con esta codificación base64 para ejecutar tu página. No es bueno.

Además, este código no se utilizaba. En ninguna parte de la aplicación se renderizaba realmente la ilustración de las características de GCL. Así que simplemente eliminé el archivo. Sin problemas. Al volver a ejecutar el npm run build con analyze true, vimos un fragmento de página mucho mejorado. Ahora hablaré de más mejoras sobre esto más adelante. Pero por ahora estaba bastante satisfecho con esto. Bajar de 11 a menos de 7.5, es una mejora bastante buena en el tamaño total. Yay. Y sólo para confirmar, volví a ejecutar las herramientas de desarrollo de Lighthouse y vi que, bueno, la Pintura de Contenido más Grande mejoró de 17.6 segundos, más o menos en unas pocas ejecuciones, a 13.2. Pero curiosamente, la puntuación general de performance en realidad no mejoró. Y creo que esto se debe a que la puntuación general de performance es un factor de problemas incluyendo LCP, y LCP sólo puede pesar hasta cierto punto. Así que más allá de cierto punto, LCP es tan malo como puede ser. Más adelante, veremos que mejora, lo prometo. Pero sí, todavía cuatro segundos y medio, más o menos, mejoraron la Pintura de Contenido más Grande o cuánto tiempo tarda en pintar la cosa visual más grande en las páginas, creo que es una buena mejora para el usuario. Así que agridulce.

6. Conclusiones de la Investigación de Rendimiento

Short description:

Mis conclusiones aquí fueron: uno, todavía es realmente divertido investigar el rendimiento de aplicaciones no optimizadas. Dos, audita regularmente tus analizadores de webpack y de paquetes. Tres, algunas métricas pueden requerir múltiples correcciones antes de mejorar. LCP mejoró, pero la puntuación general de rendimiento no lo hizo y eso está bien.

Mis conclusiones aquí, fueron: uno, todavía es realmente divertido investigar el performance de aplicaciones no optimizadas. Encontrar fragmentos extraños y extravagantes como este. Dos, similar a cómo podrías querer ejecutar regularmente todas las páginas de tu sitio para ver si están funcionando bien, incluso si son lentas, audita regularmente tus, tus analizadores de webpack, tu analizador de paquetes, quizás ver si hay algún fragmento o paquete humorísticamente grande en algún lugar de allí. Y tres, algunas métricas requerirán múltiples correcciones antes de que se produzca una mejora. LCP mejoró, pero la puntuación general de performance no lo hizo y eso está bien. Mientras se produzca un beneficio para el usuario, estoy contento.

7. Problema con las Exportaciones de Barril y el Tree Shaking

Short description:

Tres archivos index.js gigantes son un síntoma de las exportaciones de barril y de no estar haciendo tree shaking. Las exportaciones de barril son un patrón común en JavaScript donde un archivo de índice exporta múltiples archivos. La teoría detrás del tree shaking es que elimina el código no utilizado de las dependencias antes de la compilación. Sin embargo, en este caso, las partes no utilizadas del barril no se eliminaron.

Pero bien, echemos otro vistazo a esa salida del analizador de paquetes. Tres, gigantes archivos index.js. ¿Qué está pasando ahí? Ahora, esto es un síntoma de las exportaciones de barril y de no estar haciendo tree shaking, dos términos que deberíamos explicar. La exportación de barril es un patrón común en JavaScript cuando algún archivo, como un archivo de índice, exporta un montón de otros archivos. Es conveniente para que quien quiera importar esas otras cosas, pueda tomarlas de un solo lugar, ese único barril. Y en teoría, el tree shaking, que es el proceso de eliminar el código no utilizado de tus dependencias antes de que entren en la compilación, debería eliminar las partes del barril que no se utilizan. En este caso, parece que no lo están.

8. Mejorando el rendimiento del paquete y la regla ESLint

Short description:

Y solo para confirmar, solo se encontraron 34 importaciones para el paquete FortAwesome/ProLiteSVGIcons. Importar directamente desde los archivos individuales en lugar de la exportación de barril mejoró dramáticamente el paquete. El problema no estaba con Next.js o las importaciones/exportaciones de barril, sino con las herramientas de la época. Se escribió una regla ESLint para prevenir el uso accidental de las exportaciones de barril. El rendimiento mejoró con Contentful Paint LCP, tiempo total de bloqueo e índice de velocidad. El rendimiento ahora está en el área promedio.

Y solo para confirmar esto, realicé una búsqueda, ¿cuántas veces se importa este paquete FortAwesome/ProLiteSVGIcons? Solo 34 veces. Ahora, en realidad he usado este paquete antes. Es realmente agradable. Es una colección rápida y bien construida de iconos SVG de diferentes pesos. Y todos están bastante afinados para el rendimiento. Ninguno de ellos es enorme. Por lo que solo 34 importaciones de él kind of raised my alarm bells de algo raro, algo sospechoso está sucediendo aquí. 34 es un número bastante bajo.

Entonces, probé algo. Intenté, en lugar de importar desde la exportación de barril, porque he visto exportaciones de barril que no se han sacudido antes. Intenté importar directamente desde los archivos que contienen los activos. En lugar de importar, digamos, tanto los iconos de ábaco como de bebé desde la raíz, el barril, los importé desde sus archivos individuales. ¡Y voilà! Aplicar esa solución en las 34 importaciones de iconos SVG ligeros mejoró dramáticamente el paquete. Redujo mi número de gigantes barriles index.js de tres a dos. Lo que significaba que esa prueba de concepto mostrando qué pasaría si ya no usaba la exportación de barril fue, de hecho, una mejora significativa para la aplicación! Ahora, debo señalar aquí, Next.js 13.1, que se lanzó después de que hice esta investigación, mejoró bastante la detección de importaciones de barril para el tree shaking. Y creo que más tarde, las versiones posteriores de Next.js hicieron más trabajo para mejorar la situación. Así que el problema aquí ya no es Next.js. El problema ciertamente no son las importaciones de barril o las exportaciones de barril. El problema es simplemente que las herramientas de la época no soportaban este caso de uso y desde entonces se ha parcheado. Pero de todos modos, escribí una regla ESLint porque es una buena idea escribir reglas ESLint o piezas generales de automatización que eviten que las personas hagan cosas que no quieres que hagan en el futuro. Aunque había arreglado todas estas importaciones ahora, queríamos asegurarnos de que alguien no introdujera accidentalmente un nuevo uso de las exportaciones de barril. Esta regla ESLint dice que para cualquier declaración de importación con un valor de fuente que provenga de fordawesome cualquier cosa como iconos S3G sin nada después de él obtendría un informe de contexto diciéndote que uses la ruta individual. Puedes ver en la entrada de mi blog que enlazaré más tarde que también escribí un fixer para arreglar automáticamente cualquier importación lo cual fue realmente útil para aplicar automáticamente en toda la base de código.

Volviendo a ejecutar el rendimiento. Sí, finalmente vimos una mejora de 36 a 51. Mejoramos el Contentful Paint LCP de 13 a 12 más o menos. También mejoramos significativamente el tiempo total de bloqueo lo que me hace pensar que el análisis de scripts fue un problema aquí y mejoramos el índice de velocidad. Así que estoy bastante contento con esto. Por fin el rendimiento ya no estaba en rojo. Al menos estaba en amarillo, lo que llaman área promedio.

9. Mejorando el rendimiento y eliminando el código muerto

Short description:

13.2 fue bastante, bastante lento. Así que me alegra que lo hayamos mejorado. Algunas conclusiones: 1. Asegúrate de que tu herramienta soporte el tree shaking y las exportaciones/importaciones de barril. 2. Prueba de concepto de correcciones más grandes antes de invertir demasiado tiempo. 3. Automatiza las buenas prácticas para ahorrar tiempo y evitar la aplicación manual. El código no utilizado es perjudicial para la legibilidad y los tiempos de construcción. Una herramienta increíble llamada Knip ayuda a identificar y eliminar el código muerto.

13.2 fue bastante, bastante lento. Así que me alegra que lo hayamos mejorado. Algunas conclusiones. Uno, asegúrate de que tu tree shaking grandes dependencias, de nuevo las exportaciones de barril, las importaciones de barril, totalmente bien. Es un patrón muy válido en muchos casos. Solo asegúrate de que tu tooling los soporte bien. Dos, es una buena idea si vas a hacer una corrección más grande como escribir una regla personalizada de ESLint para probar el concepto. Asegúrate de que no estás gastando demasiado tiempo haciendo algo que no te dará mucho beneficio. Y tres, ama la automation. Siempre que puedas hacer cumplir automáticamente una buena práctica, hazlo de esa manera para que no tengas que hacer cumplir manualmente o limpiar errores o malos usos de ella más tarde.

Genial. Hablando de código no utilizado, esto no fue tanto una investigación de performance como una buena práctica general. Digamos que tienes una función que nunca se llama. Sería bueno tener una herramienta que te diga que este es código muerto. Deberías borrarlo. O digamos un tipo, una interfaz, que tal vez antes estaba asociada con una función pero ya no se usa. O tal vez incluso tienes una dependencia que solía ser utilizada tal vez y ya no lo es. Sería bueno tener algo que te diga que esto está muerto. Por favor, elimínalo. Y el código no utilizado es malo. Quiero que me digan que está muerto porque el código no utilizado tiene dos grandes inconvenientes. Por un lado, hace que tus archivos fuente sean menos legibles. Hay más cosas que analizar cuando estás tratando de entender. Y dos, a menudo causa compilaciones más largas. Al menos, las dependencias que no se utilizan ocupan tiempo en tus instalaciones tu npmci o equivalentes. Y si estás haciendo algún tipo de linting y/o construyendo etc. en tu código fuente, toman tiempo para ser linted, construido y así sucesivamente. Y todo eso se suma para causar que el desarrollo sea más lento para hacer que tu dev se ralentice, lo cual es malo porque quieres que tus devs trabajen lo más rápido y eficientemente posible. Afortunadamente, hay esta increíble herramienta. Mira esta ridícula vaca que hicieron llamada Knip.

10. Uso de Knip para encontrar código no utilizado

Short description:

Knip es una herramienta que encuentra código no utilizado en tu proyecto. Se puede instalar como una dependencia de desarrollo y ejecutar con configuraciones predeterminadas. Hay configuraciones disponibles para analizar archivos específicos. Aunque puede que no encuentre mucho en cada proyecto, sigue siendo beneficioso para la habilitación del desarrollador y la prevención de problemas futuros. Asegúrate de que tus desarrolladores estén contentos y considera agregar herramientas útiles. Las soluciones preventivas conocidas son valiosas, y Knip puede descubrir cantidades significativas de código no utilizado. Recuerda, '¡Knip antes de enviarlo!'

Knip hace lo que quiero. Encuentra código no utilizado. Así que sin entrar demasiado en ventas sobre ello, puedes instalarlo como una dependencia de desarrollo opcionalmente y luego puedes simplemente ejecutar npx knip y ejecutará algunas configuraciones predeterminadas y encontrará código no utilizado para ti. Ahora, cada proyecto es diferente, así que puedes configurarlo. Tiene algunas configuraciones agradables. Por ejemplo, esta toma en cuenta el archivo index de tu proyecto como el punto de entrada y luego también analiza todos los archivos de tu proyecto que son source anything.ts. Pero lo ejecutamos y realmente no encontramos mucho, pero lo comprobamos como un paso de CI porque no todas las soluciones de performance siguen directamente las investigaciones con conclusiones y puntuaciones de Lighthouse. A veces simplemente estás ejecutando la habilitación del desarrollador que es un buen objetivo por sí mismo. Quieres que tus desarrolladores sean geniales y el trabajo futuro evitado sigue siendo bueno y trabajo evitado. Así que algunas conclusiones aquí, uno, asegúrate de que tus desarrolladores estén contentos. Si hay tooling que quieres agregar que sería útil, ve si puedes encontrar tiempo para hacerlo. Dos, las soluciones preventivas conocidas definitivamente valen la pena. He visto a Kinect encontrar megabytes tras megabytes y otras bases de código. Así que sabía que Knip probablemente eventualmente encontraría este problema si no añadíamos Knip. Y tres, como dice el readme de Knip, Knip antes de enviarlo, me encanta. Pero bien, volvamos a las investigaciones.

11. Investigando el rendimiento con Emojis

Short description:

Mi favorito de todos ellos porque implica emojis y código abierto, este fue divertido. Todavía tarda unos segundos en ejecutarse, lo cual es un poco inusual. Un segundo completo, un poco más, se gasta en el plugin de emojis para Draft.js, el editor de texto. To Short parece estar haciendo algunas expresiones regulares bastante sofisticadas. NS.toShort tardó casi 700 milisegundos. Crear una expresión regular enorme tiende a ser lento. Terminamos creando un caché, donde si se estaba haciendo una gran cantidad de trabajo, lo almacenamos en una variable para que el trabajo solo necesite hacerse la primera vez que se llama a la función. La pausa se resolvió en su mayoría, y subimos de 51 a 65, casi 15 puntos en total mejor. La pintura más grande cayó de 12 a siete. El tiempo total de bloqueo se volvió verde. El índice de velocidad mejoró. Enviamos esta mejora de caché a la dependencia Upstream, la biblioteca de código abierto.

Mi favorito de todos ellos porque implica emojis y código abierto, este fue divertido. Echa un vistazo a esta grabación. En las herramientas de desarrollo y la pestaña performance recargamos, rastreamos y medimos. Vemos que incluso después de que la página ha cargado el título, lo que significa que los scripts se han cargado, todavía tarda unos segundos en ejecutarse, lo cual es un poco inusual incluso para los servidores de desarrollo local.

Y si miramos el perfil que se procesó podemos ver que hay, mientras la página está ejecutando sus scripts, un par de segundos de blanco total antes de llegar a la página de inicio. Y si nos acercamos allí y solo miramos, vemos que hay una tarea larga, eso es esa rayas rojas que indican que está pasando demasiado. Y dentro de eso, un segundo completo, un poco más, se gasta en el plugin de emojis para Draft.js, el editor de texto. Y gran parte de eso se gasta repetidamente en esta función NS.toShort.

¿Qué está pasando aquí? To Short parece estar haciendo algunas expresiones regulares bastante sofisticadas. Ahora en las herramientas de desarrollo, si haces clic en donde el nombre de la función se da un enlace azul, ¡aha! Te llevan a donde está esa función en el código fuente en tus herramientas de desarrollo, y mira esto, está anotado que NS.toShort tardó casi 700 milisegundos. Ese es el tiempo que se pasa dentro de esa función. 700 milisegundos solo en esta función. Eso es un cuello de botella de performance si alguna vez he visto uno.

Entonces, ¿qué está pasando aquí? Ahora en realidad tuve un tiempo realmente divertido investigando esto con otra persona de código abierto, un chico muy agradable llamado Marvin H. Ha estado escribiendo una gran serie de publicaciones de blog llamada Acelerando la Web. Los he enlazado más adelante, lo recomendaría encarecidamente. Marvin y yo nos metimos en una llamada de Zoom y miramos este NS.toShort. Aquí hay una simplificación de su implementación. En esencia, toma una cadena y ejecuta un utilitario replaceAll en la cadena con una enorme expresión regular que contiene todo tipo de emojis. Ahora, crear una enorme expresión regular tiende a ser lento si la estás creando dinámicamente basándote en muchas cosas, lo cual estaba haciendo esta función. De nuevo, estoy simplificando demasiado la investigación, lee la publicación del blog si quieres más, pero lo que terminamos haciendo en uno o dos lugares fue crear un caché, donde si se estaba haciendo una gran cantidad de trabajo, digamos, creando una enorme expresión regular, lo almacenamos en una variable para que el trabajo solo necesite hacerse la primera vez que se llama a la función. Ooh, genial. Me hizo feliz. Y solo confirmando al volver a ejecutar performance, la pausa se resolvió en su mayoría, y vaya, mira eso. Subimos de 51 a 65, casi 15 puntos en total mejor. La pintura más grande cayó de 12 a siete. El tiempo total de bloqueo se volvió verde. El índice de velocidad mejoró. Este fue un cambio feliz para mí. Así que en realidad enviamos esto como una mejora, este caché a la dependencia Upstream, la biblioteca de código abierto.

12. Conclusión y puntos clave

Short description:

Se fusionó unos meses después. Mientras tanto, utilicé el paquete npm-patch para aplicarlo localmente para poder obtener los cambios antes de que surgieran en el repositorio Upstream. Rendimiento bueno. Encontramos iframes y utilizamos la carga perezosa. Eliminamos archivos no utilizados y solucionamos el tree shaking con una regla de ESLint. Knip evitó el código no utilizado. Almacenamos en caché el resultado de un cálculo costoso. Recursos disponibles en línea. Muchas gracias a todos. Saludos.

Se fusionó unos meses después. Mientras tanto, utilicé el paquete npm-patch para aplicarlo localmente para poder obtener los cambios antes de que surgieran en el repositorio Upstream. Marvin y yo estábamos muy contentos con esto.

Y eso es todo lo que quería mostrar con las investigaciones de rendimiento. Hay mucho más en lo que podríamos profundizar. Podríamos profundizar en el perfilado de React, hay un gran conjunto de herramientas de desarrollo. Podríamos entrar en los bucles y hooks de React y todas estas cosas. Pero esta masterclass es remota y para la mitad del tiempo que llevaría entrar en esos temas. Así que repasemos las cosas en las que pudimos profundizar.

Performance bueno. Hay muchas razones por las que los usuarios deberían preocuparse y tú deberías preocuparte por el performance. Miramos bastantes investigaciones diferentes. Encontramos muchos iframes donde la carga perezosa fue la solución. Encontramos imágenes incrustadas ocultas yendo a las herramientas de desarrollo para encontrar donde los grandes bloques eran visibles y luego simplemente eliminando los archivos no utilizados. Vimos que el tree shaking no funcionaba para las exportaciones de barril que se solucionó con una regla de ESLint, más tarde una versión actualizada de Next.js. Vimos que el código no utilizado se evitaba en el futuro con Knip y vimos mi favorito, los emojis donde almacenamos en caché el resultado de un cálculo costoso.

Todos estos recursos están disponibles en línea. El post del blog web dev Why Speed Matters es genial. Cada una de estas cinco investigaciones tiene su propio post en mi blog y el blog de Marvin incluye acelerando el JavaScript ecosystem, parte seis. Las partes del uno al cinco también son bastante entretenidas así como nuestras siete en adelante. Eso es todo lo que tengo para ustedes. Muchas gracias a todos. Saludos. ♪♪♪

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

A Guide to React Rendering Behavior
React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
Top Content
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
Building Better Websites with Remix
React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Top Content
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
React Compiler - Understanding Idiomatic React (React Forget)
React Advanced Conference 2023React Advanced Conference 2023
33 min
React Compiler - Understanding Idiomatic React (React Forget)
Top Content
React provides a contract to developers- uphold certain rules, and React can efficiently and correctly update the UI. In this talk we'll explore these rules in depth, understanding the reasoning behind them and how they unlock new directions such as automatic memoization. 
Using useEffect Effectively
React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Top Content
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
Speeding Up Your React App With Less JavaScript
React Summit 2023React Summit 2023
32 min
Speeding Up Your React App With Less JavaScript
Top Content
Too much JavaScript is getting you down? New frameworks promising no JavaScript look interesting, but you have an existing React application to maintain. What if Qwik React is your answer for faster applications startup and better user experience? Qwik React allows you to easily turn your React application into a collection of islands, which can be SSRed and delayed hydrated, and in some instances, hydration skipped altogether. And all of this in an incremental way without a rewrite.
Routing in React 18 and Beyond
React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Top Content
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.

Workshops on related topic

React Performance Debugging Masterclass
React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Top Content
Featured WorkshopFree
Ivan Akulov
Ivan Akulov
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
Concurrent Rendering Adventures in React 18
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
Maurice de Beijer
Maurice de Beijer
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Hooks Tips Only the Pros Know
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
Maurice de Beijer
Maurice de Beijer
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React, TypeScript, and TDD
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
Web3 Workshop - Building Your First Dapp
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
Nader Dabit
Nader Dabit
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
Designing Effective Tests With React Testing Library
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Top Content
Featured Workshop
Josh Justice
Josh Justice
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn