1. Introducción al Rendimiento de React
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
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
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
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
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
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
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
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
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
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
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
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. ♪♪♪
Comments