JavaScript de división de código

La carga de recursos grandes de JavaScript afecta la velocidad de la página de forma significativa. Dividiendo tu JavaScript en fragmentos más pequeños y descargando solo lo necesario para para funcionar durante el inicio puede mejorar en gran medida la carga de tu página la capacidad de respuesta, lo que, a su vez, puede mejorar la Interacción con el siguiente elemento de tu página Pintura (INP).

A medida que una página descarga, analiza y compila archivos JavaScript grandes, puede que no responden durante períodos. Los elementos de la página son visibles, ya que son parte del código HTML inicial de una página y tiene el estilo CSS. Sin embargo, dado que el código JavaScript necesarios para potenciar esos elementos interactivos, así como otros scripts cargados por la página, es posible que analicemos y ejecuten el código JavaScript para que funcionen. El resultado es que el usuario puede sentir que la interacción fue significativamente retrasado o incluso roto por completo.

Esto suele suceder porque se bloquea el subproceso principal, ya que se analiza JavaScript. y se compilan en el subproceso principal. Si este proceso lleva demasiado tiempo, es posible que los elementos de página no respondan con la rapidez suficiente a las entradas del usuario. Una solución para esto es cargar solo el JavaScript necesario para que la página funcione, mientras que Diferir otro JavaScript para que se cargue más adelante mediante una técnica conocida como código la división. Este módulo se centra en la última de estas dos técnicas.

Reduce el análisis y la ejecución de JavaScript durante el inicio a través de la división de código

Lighthouse muestra una advertencia cuando la ejecución de JavaScript tarda más de 2 segundos. segundos y falla cuando tarda más de 3.5 segundos. JavaScript excesivo el análisis y la ejecución es un posible problema en cualquier punto de la página ya que tiene el potencial de aumentar el retraso de entrada de una interacción si el momento en que el usuario interactúa con la página coincide con el momento se incluyen las tareas del subproceso principal responsables de procesar y ejecutar JavaScript. en ejecución.

Más que eso, la ejecución y el análisis excesivos de JavaScript son problemático durante la carga inicial de la página, ya que este es el punto en la página en el ciclo de vida de la página que es muy probable que los usuarios interactúen con ella. De hecho, El tiempo de bloqueo total (TBT), una métrica de capacidad de respuesta a la carga, está altamente correlacionado con INP, lo que sugiere que los usuarios tienen una alta tendencia a intentar interactuar durante la carga inicial de la página.

La auditoría de Lighthouse que informa el tiempo dedicado a ejecutar cada archivo JavaScript que tu página solicita es útil, ya que puede ayudarte a identificar exactamente qué Las secuencias de comandos pueden ser candidatas para la división de código. Luego, puedes ir más allá Con la herramienta de cobertura de las Herramientas para desarrolladores de Chrome a fin de identificar exactamente qué partes de el código JavaScript de una página no se usa durante la carga.

La división de código es una técnica útil que puede reducir el JavaScript inicial de una página cargas útiles útiles. Te permite dividir un paquete de JavaScript en dos partes:

  • El código JavaScript necesario al cargar la página y, por lo tanto, no se puede cargar en ninguna otra tiempo.
  • JavaScript restante que se puede cargar más adelante, con mayor frecuencia cuando el usuario interactúa con un elemento interactivo determinado en la página.

La división de código se puede realizar con la sintaxis import() dinámica. Esta sintaxis, a diferencia de los elementos <script>, que solicitan un determinado recurso JavaScript durante el inicio; envía una solicitud de un recurso de JavaScript más adelante. ciclo de vida de la página.

document.querySelectorAll('#myForm input').addEventListener('blur', async () => {
  // Get the form validation named export from the module through destructuring:
  const { validateForm } = await import('/validate-form.mjs');

  // Validate the form:
  validateForm();
}, { once: true });

En el fragmento de JavaScript anterior, el módulo validate-form.mjs es descargar, analizar y ejecutar solo cuando un usuario enumera cualquiera de los elementos de un formulario <input>. En esta situación, el recurso JavaScript responsable de que impulsa la lógica de validación del formulario solo se involucra en la página cuando y qué es más probable que se use realmente.

Los agrupadores de JavaScript, como webpack, Parcel, Rollup y esbuild, se pueden que está configurado para dividir paquetes de JavaScript en fragmentos más pequeños encontrar una llamada dinámica import() en tu código fuente. La mayoría de estas herramientas esta acción se realizará automáticamente, pero esbuild en particular requiere que habilites esta la optimización de las conversiones.

Notas útiles sobre la división de código

Mientras que la división de código es un método eficaz para reducir la contención del subproceso principal durante la carga inicial de la página, resulta útil tener en cuenta algunos aspectos si decides auditar el código fuente de JavaScript para las oportunidades de división del código.

Si puedes, usa un agrupador

Es una práctica común que los desarrolladores usen módulos de JavaScript durante el de desarrollo de software. Es una excelente mejora en la experiencia del desarrollador mejora la legibilidad y el mantenimiento del código. Sin embargo, hay algunas Características de rendimiento deficientes que pueden generarse al enviar JavaScript módulos a producción.

Lo más importante es que debes usar un agrupador para procesar y optimizar el código fuente el código, incluidos los módulos que quieres dividir en el código. Los empaquetadores son muy eficaces para no solo aplicar optimizaciones al código fuente de JavaScript, bastante eficaz para equilibrar las consideraciones de rendimiento, como el tamaño del paquete frente al índice de compresión. La eficacia de la compresión aumenta con el tamaño del paquete, pero los agrupadores también intentan garantizar que no sean tan grandes como para tareas largas debido a la evaluación de los guiones.

Los agrupadores también evitan el problema de enviar una gran cantidad de módulos sin agrupar a través de la red. Las arquitecturas que usan módulos de JavaScript suelen tener conjuntos árboles de módulos complejos. Cuando los árboles de módulos no están agrupados, cada módulo representa una una solicitud HTTP separada y la interactividad en tu app web puede retrasarse si no agrupas módulos. Si bien es posible utilizar el Sugerencia de recursos <link rel="modulepreload"> para cargar árboles de módulos grandes lo antes posible, los paquetes de JavaScript siguen siendo preferibles a los de un rendimiento de carga punto de vista.

No inhabilites la compilación de transmisión por accidente

El motor de JavaScript V8 de Chromium ofrece una serie de optimizaciones listas para usar para asegurarte de que el código JavaScript de producción se cargue de la manera más eficiente posible. Una de estas optimizaciones se conoce como compilación de transmisión, que, al igual que análisis incremental de HTML transmitido al navegador (compila fragmentos transmitidos de JavaScript a medida que llegan desde la red.

Hay un par de formas de asegurarse de que la compilación de transmisión se realice aplicación web en Chromium:

  • Transforma tu código de producción para evitar usar módulos de JavaScript. Envasadores transformar tu código fuente de JavaScript en función de un destino de compilación el objetivo suele ser específico de un entorno determinado. V8 aplicará la transmisión compilación a cualquier código de JavaScript que no use módulos, y puedes configurar tu agrupador para transformar el código del módulo de JavaScript en una sintaxis que no use módulos de JavaScript ni sus funciones.
  • Si quieres enviar módulos de JavaScript a producción, usa el .mjs . Ya sea que tu JavaScript de producción use módulos, hay Falta de tipo de contenido especial para JavaScript que usa módulos en comparación con JavaScript que no lo hace. En lo que concierne a V8, debes inhabilitar la transmisión de contenido. compilación cuando envías módulos de JavaScript en producción con .js . Si usas la extensión .mjs para los módulos de JavaScript, V8 puede asegurarte de que la compilación de transmisión para código JavaScript basado en módulos no sea está roto.

No dejes que estas consideraciones te desanimen de usar la división de código. Programación la división es una manera eficaz de reducir las cargas útiles iniciales de JavaScript para los usuarios pero si usas un agrupador y sabes cómo preservar la transmisión de V8 de compilación, puedes asegurarte de que tu código JavaScript de producción sea rápido tanto como sea posible.

Demostración de importación dinámica

webpack

webpack se envía con un complemento llamado SplitChunksPlugin, que te permite configurar la forma en que el agrupador divide los archivos JavaScript. webpack reconoce tanto sentencias import() dinámicas y import estáticas. El comportamiento de SplitChunksPlugin se puede modificar especificando la opción chunks en su actual:

  • chunks: async es el valor predeterminado y hace referencia a llamadas dinámicas import().
  • chunks: initial hace referencia a llamadas estáticas import.
  • chunks: all abarca las importaciones dinámicas import() y estáticas, lo que te permite para compartir fragmentos entre las importaciones async y initial.

De forma predeterminada, cada vez que webpack encuentra una sentencia import() dinámica. it crea un fragmento separado para ese módulo:

/* main.js */

// An application-specific chunk required during the initial page load:
import myFunction from './my-function.js';

myFunction('Hello world!');

// If a specific condition is met, a separate chunk is downloaded on demand,
// rather than being bundled with the initial chunk:
if (condition) {
  // Assumes top-level await is available. More info:
  // https://v8.dev/features/top-level-await
  await import('/form-validation.js');
}

La configuración predeterminada de webpack para el fragmento de código anterior genera dos fragmentos separados:

  • El fragmento main.js, que webpack clasifica como un fragmento initial, que Incluye los módulos main.js y ./my-function.js.
  • El fragmento async, que incluye solo form-validation.js (que contiene un hash de archivo en el nombre del recurso, si está configurado). Este fragmento solo se descargó si condition es verdadero.

Esta configuración te permite diferir la carga del fragmento form-validation.js hasta es realmente necesario. Esto puede mejorar la capacidad de respuesta de carga al reducir las secuencias de comandos evaluación durante la carga inicial de la página. Descarga y evaluación de la secuencia de comandos para el fragmento form-validation.js se produce cuando se cumple una condición específica, en en cuyo caso, se descarga el módulo importado de forma dinámica. Un ejemplo podría ser un condición en la que un polyfill solo se descarga en un navegador en particular, o bien, En el ejemplo anterior, el módulo importado es necesario para la interacción del usuario.

Por otro lado, si cambias la configuración de SplitChunksPlugin para especificar chunks: initial garantiza que el código se divida solo en los fragmentos iniciales. Son como los que se importan estáticamente o que se enumeran en el archivo entry de webpack propiedad. Si observas el ejemplo anterior, el fragmento resultante sería una combinación de form-validation.js y main.js en un solo archivo de secuencia de comandos, lo que puede empeorar el rendimiento de carga inicial de la página.

Las opciones de SplitChunksPlugin también se pueden configurar para separar elementos más grandes secuencias de comandos en varias más pequeñas, por ejemplo, mediante la opción maxSize para indicar a webpack que divida los fragmentos en archivos separados si superan el límite especificadas por maxSize. Dividir los archivos de secuencia de comandos grandes en archivos más pequeños mejorar la capacidad de respuesta de la carga, como, en algunos casos, la evaluación de secuencias de comandos con uso intensivo de CPU el trabajo se divide en tareas más pequeñas, que tienen menos probabilidades de bloquear el trabajo subproceso durante períodos más prolongados.

Además, generar archivos JavaScript más grandes también significa que las secuencias de comandos tienen más probabilidades de sufrir invalidación de caché. Por ejemplo, si envías un secuencia de comandos grande con framework y código propio de la aplicación, toda la un paquete se puede invalidar si solo se actualiza el framework, pero no hay nada más el recurso empaquetado.

Por otro lado, los archivos de secuencia de comandos más pequeños aumentan la probabilidad de que se muestre el visitante recupera los recursos de la caché, lo que hace que la página se cargue más rápido en visitas repetidas. Sin embargo, los archivos más pequeños se benefician menos de la compresión que los más grandes y puede aumentar el tiempo de ida y vuelta de red en cargas de páginas con una en la caché del navegador. Se debe tener cuidado para lograr un equilibrio entre el almacenamiento en caché la eficiencia, la eficacia de la compresión y el tiempo de evaluación de los guiones.

Demostración de webpack

Demostración de SplitChunksPlugin de webpack

Ponga a prueba sus conocimientos

El tipo de sentencia import que se usa cuando se realiza código la división?

import() dinámico
Correcto.
Estático import.
Vuelve a intentarlo.

¿Qué tipo de sentencia import debe estar en la parte superior. de un módulo de JavaScript y en ninguna otra ubicación?

import() dinámico
Vuelve a intentarlo.
Estático import.
Correcto.

Cuando se usa SplitChunksPlugin en webpack, ¿cuál es la diferencia entre un bloque de async y un ¿Bloque de initial?

Los fragmentos de async se cargan con import() dinámico. y los fragmentos initial se cargan mediante import
Correcto.
Los fragmentos de async se cargan con import estático. y initial los fragmentos se cargan usando recursos import()
Vuelve a intentarlo.

A continuación: Carga imágenes y elementos <iframe> de forma diferida

Aunque suele ser un recurso bastante costoso, JavaScript no es el el único tipo de recurso del que puedes diferir la carga. Imagen y elementos <iframe> son recursos potencialmente costosos en sí mismos. Al igual que JavaScript, Puede diferir la carga de imágenes y elementos <iframe> mediante una carga diferida los cambios, lo que se explica en el siguiente módulo de este curso.