¿Qué sucede cuando un script se carga como "preload" / "modulepreload"?

Sep 06 2020

Hay un artículo muy interesante en web.dev sobre el módulo del trabajador https://web.dev/module-workers/ donde tenemos la capacidad de cargar el trabajador como módulo precargado, lo que significa que se pueden precargar e incluso pre-analizar y precargar sus dependencias (https://web.dev/module-workers/#preload-workers-with-modulepreload).

Si estoy en lo correcto, no solo los Web-Workers se pueden cargar como módulo de precarga, esto es aplicable a cualquier script js, fuente, css, etc., como

<link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">

<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">

Hay un dicho en este artículo que me molesta mucho:

Los módulos precargados también pueden ser utilizados tanto por el hilo principal como por los trabajadores del módulo. Esto es útil para los módulos que se importan en ambos contextos, o en los casos en los que no es posible saber de antemano si un módulo se utilizará en el hilo principal o en un trabajador.

¿Significa esto que la carga de módulos también almacena en caché el código analizado, lo que significa que los módulos que se usan en el hilo principal y en un trabajador no se analizarán nuevamente, si lo hemos incluido usando la declaración de importación en la parte superior?

Sin embargo, esto no sucede, siempre que importamos módulos en cualquier dominio (subproceso principal, subproceso de trabajo), ejecutan su importación de forma independiente y luego, en el futuro, se refieren a sus instancias almacenadas en caché analizadas en sus propios dominios.

Estoy realmente confundido, qué es exactamente lo que el autor está tratando de explicar. Y cómo podemos implementarlo.

Artículos relacionados: https://developers.google.com/web/updates/2017/12/modulepreload#does_preloading_modules_help_performance

Respuestas

Kaiido Sep 12 2020 at 10:28

No estoy seguro de dónde sacó esta idea este artículo, pero al leer las especificaciones, no veo evidencia de que

Los módulos precargados también pueden ser utilizados tanto por el hilo principal como por los trabajadores del módulo.


Si verificamos las especificaciones, la búsqueda y el proceso del algoritmo de recursos vinculados para modulepreloadenlaces lo hace en el paso 5

  1. Deje que el objeto de configuración sea ​​el objeto de configuración relevantelink del documento de nodo del elemento .

Este objeto de configuración se pasa luego en el paso 11 al algoritmo de gráfico de script de módulo de precarga de módulo , que llamará a buscar un script de módulo único y buscará los descendientes de un enlace , que en última instancia también llamará a buscar un script de módulo único , con el mismo objeto de configuración .

Este objeto de configuración es donde se encontrará el mapa del módulo , y este mapa del módulo se utilizará para buscar un único script de módulo para evitar solicitar varias veces el mismo módulo (un caché).

  1. Deje que moduleMap sea ​​el mapa del módulo del objeto de configuración del mapa del módulo .

  2. Si moduleMap [url] es "fetching", espere en paralelo hasta que cambie el valor de esa entrada, luego ponga en cola una tarea en la fuente de tareas de red para continuar con la ejecución de los siguientes pasos.

  3. Si moduleMap [url] existe, complete de forma asincrónica este algoritmo con moduleMap [url] y regrese.

Probablemente debería tenerse en cuenta que, aunque este algoritmo crea un script de módulo , todavía no lo ejecuta.


Entonces, a partir de ahí, podemos ver que los modulepreloadenlaces no solo buscarán el recurso vinculado, sino todos los sub-recursos e incluso prepararán scripts de módulo para cada uno de estos recursos, lo que corresponde mucho a lo que este artículo afirma de otra manera.

Sin embargo, esto no es suficiente para concluir nada con respecto a la cita problemática.

Tenemos que ir a verificar las especificaciones sobre el constructor de Trabajadores dedicado , que llamará al algoritmo ejecutar un trabajador pasando la configuración del objeto del mismo documento que nuestro modulepreloadenlace estaba usando, esta vez llamado " configuración externa ".

En el paso 8 de esta ejecución de un algoritmo de trabajo , solicita

  1. Configure un objeto de configuración del entorno de trabajo con el contexto de ejecución del reino y la configuración externa , y deje que la configuración interna sea ​​el resultado.

Y este conjunto hasta objeto un ambiente trabajador configuración algoritmo utilizará solamente del documento ajustes fuera para establecer el inherited originvalor interno y los nuevos ajustes del objeto 's top-level originpropiedad.

Esta nueva configuración del objeto 's mapa módulo es el de su alcance mundial , que es ' inicialmente vacía '.

El objeto de configuración del entorno del trabajador no hereda su mapa de módulo de la configuración externa .

Así que cuando el trabajador sí llamar éstos traen una única secuencia de comandos del módulo y buscar a los descendientes de y enlace algoritmos como parte de buscar un gráfico de la escritura del trabajador módulo , el módulo de mapa se comprobará es su propio interior de la configuración 's mapa módulo y allí, no encontrará los scripts de módulo que modulepreloadha creado nuestro enlace.


Entonces, según mi lectura de las especificaciones, diría que los modulepreloadenlaces solo ayudan para los trabajadores del módulo es que la caché HTTP ya habrá descargado todos los archivos en el gráfico. Si va a usar estos módulos solo en Worker, entonces hacer que prepare los scripts del módulo en el lado del documento es realmente contraproducente, y un prefetchenlace simple podría funcionar mejor, excepto que tendría que crear uno de esos enlaces por sub-recurso.

Dolly Sep 16 2020 at 23:59

Kaiido Gracias por la respuesta detallada. Es de mucha ayuda.

También busqué mucho sobre esta cita problemática y luego inicié un problema en web.dev si podían actualizar el contenido. Puede realizar un seguimiento de Issue

Uno de los trabajos más pesados ​​para JS Engine es analizar / compilar ( Qué es Parse / Compile ) nuestro código y juega un papel importante en el tiempo para interactuar de una página web y también hay muchas formas en las que podemos mejorar TTI como solo enviar el código que un usuario necesita ( división de código por paquete web, fragmentos, etc.), minificación, agitación de árboles, almacenamiento en caché http , módulos de trabajadores, etc. y también sin olvidar la precarga

Definición real de precarga:

La forma básica en que puede utilizar la precarga es cargar antes los recursos detectados con retraso. Si bien el precargador del navegador descubre la mayoría de los recursos basados ​​en el marcado, no todos los recursos se basan en el marcado. Algunos de los recursos están ocultos en CSS y en JavaScript, y el navegador no puede saber que los necesitará hasta que sea bastante tarde. Entonces, en muchos casos, estos recursos terminan retrasando el primer renderizado, el renderizado de texto o la carga de partes críticas de la página.

En breve:

Descargue un recurso (preparación + compilación) porque sabe que lo necesitará, pero aún no desea ejecutarlo.

Anteriormente, si inyectamos el script en el punto en el que queremos que se ejecute, el navegador tendrá que descargar el script antes de que se pueda ejecutar (NOTA: el navegador tiene que hacer muchas cosas antes de ejecutar su código), lo que puede llevar un tiempo mientras. Pero Preload resuelve esto.

Creo que el autor está tratando de explicar lo mismo, es decir, módulos precargados e incluso pre-analizados (no ejecutar + el código de bytes compilado se almacena en caché) usando el enlace rel = etiqueta "modulepreload" para una evaluación posterior (se puede omitir la recompilación).

Y finalmente creo que mis consultas están resueltas. Muchas gracias!

Un par de enlaces útiles:

  • https://developers.google.com/web/updates/2017/12/modulepreload
  • https://3perf.com/blog/link-rels/