Dos formas de precarga: etiquetas <link> y encabezados HTTP

Demián Renzulli
Demián Renzulli

En este codelab, implementarás la carga previa de dos maneras: con <link rel="prefetch"> y con el encabezado HTTP Link.

La app de ejemplo es un sitio web que tiene una página de destino promocional con un descuento especial para la camiseta más vendida de la tienda. Dado que la página de destino vincula a un solo producto, es seguro suponer que un alto porcentaje de los usuarios navegará a la página de detalles del producto. Esto hace que la página del producto sea un gran candidato para la carga previa en la página de destino.

Cómo medir el rendimiento

Primero, establece el rendimiento de referencia:

  1. Haz clic en Remix to Edit para que el proyecto sea editable.
  2. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.
  3. Presiona "Control + Mayúsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
  4. Haga clic en la pestaña Red.

  5. En la lista desplegable Restricción, selecciona 3G rápido para simular un tipo de conexión lenta.

  6. Para cargar la página del producto, haz clic en Comprar ahora en la app de ejemplo.

La página product-details.html tarda alrededor de 600 ms en cargarse:

Panel de red que muestra los tiempos de carga de product-details.html

Para mejorar la navegación, inserta una etiqueta prefetch en la página de destino para obtener la página product-details.html de antemano:

  • Agrega el siguiente elemento <link> al principio del archivo views/index.html:
<!doctype html>
  <html>
    <head>
       <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">

      <link rel="prefetch" href="/product-details.html" as="document">
      ...
</head>

El atributo as es opcional, pero se recomienda. Ayuda al navegador a establecer los encabezados correctos y determinar si el recurso ya está en la caché. Algunos valores de ejemplo para este atributo son: document, script, style, font, image y otros.

Para verificar que la carga previa funcione, haz lo siguiente:

  1. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.
  2. Presiona "Control + Mayúsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
  3. Haga clic en la pestaña Red.

  4. En la lista desplegable Restricción, selecciona 3G rápido para simular un tipo de conexión lenta.

  5. Desmarca la casilla de verificación Inhabilitar la caché.

  6. Vuelve a cargar la app.

Ahora, cuando se carga la página de destino, también se carga la página product-details.html, pero con la prioridad más baja:

Panel de red que muestra el archivo product-details.html recuperado previamente.

La página se mantiene en la caché de HTTP durante cinco minutos, después de los cuales se aplican las reglas normales de Cache-Control para el documento. En este caso, product-details.html tiene un encabezado cache-control con un valor de public, max-age=0, lo que significa que la página se conserva durante un total de cinco minutos.

Vuelve a evaluar el rendimiento

  1. Vuelve a cargar la app.
  2. Para cargar la página del producto, haz clic en Comprar ahora en la app de ejemplo.

Consulta el panel Red. Existen dos diferencias en comparación con el registro de red inicial:

  • La columna Tamaño muestra "caché de carga previa", lo que significa que este recurso se recuperó de la caché del navegador en lugar de la red.
  • La columna Tiempo muestra que el tiempo que tarda en cargarse el documento ahora es de alrededor de 10 ms.

Esto representa una reducción de aproximadamente el 98% en comparación con la versión anterior, que tardaba alrededor de 600 ms.

Panel de red que muestra product-details.html recuperado de la caché con carga previa.

Crédito adicional: Usa prefetch como mejora progresiva

La carga previa se implementa mejor como una mejora progresiva para los usuarios que navegan con conexiones rápidas. Puedes usar la API de Network Information para verificar las condiciones de la red y, en función de eso, insertar etiquetas de precarga de forma dinámica. De esta manera, puedes minimizar el consumo de datos y ahorrar costos para los usuarios que tienen planes de datos lentos o costosos.

Para implementar la carga previa adaptativa, primero quita la etiqueta <link rel="prefetch"> de views/index.html:

<!doctype html>
  <html>
    <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
       <link rel="prefetch" href="/product-details.html" as="document">
       ...
    </head>

Luego, agrega el siguiente código a public/script.js para declarar una función que inyecte de forma dinámica la etiqueta prefetch cuando el usuario tenga una conexión rápida:

function injectLinkPrefetchIn4g(url) {
    if (window.navigator.connection.effectiveType === '4g') {
        //generate link prefetch tag
        const linkTag = document.createElement('link');
        linkTag.rel = 'prefetch';
        linkTag.href = url;
        linkTag.as = 'document';

        //inject tag in the head of the document
        document.head.appendChild(linkTag);
    }
}

La función funciona de la siguiente manera:

  • Verifica la propiedad effectiveType de la API de Network Information para determinar si el usuario tiene una conexión 4G (o más rápida).
  • Si se cumple esa condición, se genera una etiqueta <link> con prefetch como el tipo de sugerencia, se pasa la URL que se recuperará previamente en el atributo href y se indica que el recurso es un document HTML en el atributo as.
  • Por último, inserta la secuencia de comandos de forma dinámica en el head de la página.

A continuación, agrega script.js a views/index.html, justo antes de la etiqueta </body> de cierre:

<body>
      ...
      <script src="/script.js"></script>
</body>

Solicitar script.js al final de la página garantiza que se cargue y ejecute después de que se analice y cargue la página.

Para asegurarte de que la carga previa no interfiera con los recursos críticos de la página actual, agrega el siguiente fragmento de código para llamar a injectLinkPrefetchIn4g() en el evento window.load:

<body>
      ...
      <script src="/script.js"></script>
      <script>
           window.addEventListener('load', () => {
                injectLinkPrefetchIn4g('/product-details.html');
           });
      </script>
</body>

La página de destino ahora realiza la carga previa de product-details.html solo en conexiones rápidas. Para verificar lo siguiente:

  1. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.
  2. Presiona "Control + Mayúsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
  3. Haga clic en la pestaña Red.
  4. En la lista desplegable Restricción, selecciona En línea.
  5. Vuelve a cargar la app.

Deberías ver product-details.html en el panel Red:

Panel de red que muestra el archivo product-details.html recuperado previamente.

Para verificar que la página del producto no se precargue en conexiones lentas, sigue estos pasos:

  1. En la lista desplegable Limitación, selecciona 3G lento.
  2. Vuelve a cargar la app.

El panel Red debe incluir solo los recursos de la página de destino sin product-details.html:

Panel de red que muestra que no se está precargando product-details.html.

El encabezado HTTP Link se puede usar para recuperar previamente el mismo tipo de recursos que la etiqueta link. Decidir cuándo usar uno o el otro depende principalmente de tu preferencia, ya que la diferencia en el rendimiento es insignificante. En este caso, lo usarás para recuperar previamente el CSS principal de la página del producto y mejorar aún más su renderización.

Agrega un encabezado HTTP Link para style-product.css en la respuesta del servidor de la página de destino:

  1. Abre el archivo server.js y busca el controlador get() de la URL raíz: /.
  2. Agrega la siguiente línea al comienzo del controlador:
app.get('/', function(request, response) {
    response.set('Link', '</style-product.css>; rel=prefetch');
    response.sendFile(__dirname + '/views/index.html');
});
  1. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.
  2. Presiona "Control + Mayúsculas + J" (o "Comando + Opción + J" en Mac) para abrir DevTools.
  3. Haga clic en la pestaña Red.
  4. Vuelve a cargar la app.

Ahora, style-product.css se obtiene previamente con la prioridad más baja después de que se carga la página de destino:

Panel de red que muestra el estilo-product.css recuperado previamente.

Para navegar a la página del producto, haz clic en Comprar ahora. Consulta el panel Red:

Panel de red que muestra style-product.css recuperado de la caché de carga previa.

El archivo style-product.css se recupera de la "caché de precarga" y solo tardó 12 ms en cargarse.