Aplaza los scripts hasta que sean necesarios

Aprende cómo mejorar los Core Web Vitals aplazando los scripts hasta que sean necesarios

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2024-11-27

Aplaza los scripts hasta que sean necesarios

En este artículo mostraré y explicaré un patrón útil para cargar scripts que no son necesarios durante el inicio de la carga de la página en un momento posterior, justo antes de que sean necesarios.

Lo más efectivo que puedes hacer con JavaScript en lo que respecta a los Core Web Vitals es retrasar la carga de un recurso hasta que sea necesario. Esto eliminará JavaScript no utilizado e innecesario de la página y solo lo cargará cuando sea necesario. Esto solucionará la advertencia de Lighthouse 'reduce unused JavaScript' y también mejorará las métricas de capacidad de respuesta como Interaction to Next Paint (INP).
Hemos estado haciendo esto con imágenes durante mucho tiempo. Se llama lazy loading. Con lazy loading, una imagen que está debajo del pliegue se carga justo antes de que se desplace a la vista. De esta manera, no necesitamos cargar la imagen inmediatamente durante la carga de la página y el navegador puede dedicar sus valiosos recursos a descargar, analizar y renderizar las cosas que realmente se necesitan.

Ahora imagina que pudiéramos hacer lo mismo con scripts en lugar de imágenes. ¡Resulta que sí podemos! Desafortunadamente no es tan simple como agregar loading="lazy" a una imagen, pero con un poco de esfuerzo podemos hacerlo funcionar

Paso 1: Cargar scripts bajo demanda

Para agregar scripts a la página después de la carga de la página, necesitaremos un pequeño script que haga esto por nosotros.

function injectScript(scriptUrl, callback) {
  var script = document.createElement("script");
  script.src = scriptUrl;
  if (typeof callback === "function") {
    script.onload = function () {
      callback();
    };
  }
  document.head.appendChild(script);
}        

Esta función inyecta un script en la página web actual creando un nuevo elemento script y añadiéndolo al head del documento. El parámetro scriptUrl especifica la URL del script a inyectar. El parámetro callback es una función opcional que se ejecutará cuando el script haya terminado de cargarse. Cuando el script ha terminado de cargarse, se activa el evento onload del elemento script. Si se proporcionó una función callback, se ejecutará en ese momento.

Paso 2: Cargar scripts bajo demanda

El siguiente paso es cargar scripts bajo demanda. Hay 2 métodos comunes para hacer esto. El primero es el más fiable 'cuando una parte de la página es visible' y el segundo es el más rápido 'al interactuar'.

2a: Intersection observer

El primer método para cargar un script justo antes de que sea necesario utiliza el intersection observer. El intersection observer es un método fiable que se 'activa' cuando un elemento se cruza con la parte visible de la pantalla. Podemos usar este comportamiento para activar la descarga de un script solo cuando un elemento es visible. La desventaja de este método es que aunque un elemento esté 'en pantalla', aún podría no ser utilizado.

function injectScriptOnIntersection(scriptUrl, elementSelector) {
  var observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(function(entry) {
      if (entry.isIntersecting) {
        injectScript(scriptUrl);
        observer.unobserve(entry.target);
      }
    });
  });

  var element = document.querySelector(elementSelector);
  observer.observe(element);
}
        

Esta función toma dos parámetros: scriptUrl es la URL del script a inyectar, y elementSelector es un selector CSS para el elemento que debe activar la inyección.

La función crea un nuevo objeto IntersectionObserver y le pasa una función callback que se ejecutará cada vez que un elemento observado se cruce con el viewport. La función callback verifica si el elemento se está cruzando y, de ser así, inyecta el script y deja de observar el elemento.

Ten en cuenta que la API Intersection Observer no es compatible con todos los navegadores, por lo que es posible que necesites usar un polyfill si necesitas dar soporte a navegadores más antiguos.

injectScriptOnIntersection('script.js', '#my-element');

Esto inyectará el script cuando el elemento con ID my-element se haga visible en el viewport.

2b: Al interactuar

El método más efectivo para cargar JavaScript bajo demanda es cargarlo cuando un visitante interactúa con un determinado elemento. Por ejemplo, un formulario. La ventaja de usar este método es que probablemente nunca cargarás el script si no es necesario. La desventaja es que la acción de descarga es bastante tardía y tenemos que decidir qué eventos (mouseover, hover, touchstart, etc.) queremos escuchar.

function injectScriptOnInteraction(scriptUrl, elementSelector, eventTypes) {
  var element = document.querySelector(elementSelector);
  var eventHandler = function() {
    injectScript(scriptUrl);
    eventTypes.forEach(function(eventType) {
      element.removeEventListener(eventType, eventHandler);
    });
  };
  eventTypes.forEach(function(eventType) {
    element.addEventListener(eventType, eventHandler);
  });
}
        

Esta función toma tres parámetros: scriptUrl es la URL del script a inyectar, elementSelector es un selector CSS para el elemento que debe activar la inyección, y eventTypes es un array de tipos de eventos que deben activar la inyección (por ejemplo, ["click", "mouseover"]).

La función encuentra el elemento usando document.querySelector y le agrega event listeners para cada uno de los tipos de eventos especificados. Cuando ocurre cualquiera de los eventos especificados, se llama a la función injectScript con la URL especificada, y los event listeners se eliminan usando element.removeEventListener.

injectScriptOnInteraction(
  'script.js',
  '#my-element', 
  ['click', 'mouseover']
);

Esto inyectará el script cuando se haga clic o se pase el cursor sobre el elemento con ID my-element, y luego eliminará los event listeners.

Conclusión

Cuando los scripts no son necesarios de inmediato durante el inicio de la carga de la página, ¡es una gran idea cargarlos bajo demanda! Podemos hacer esto usando el intersection observer o al interactuar. Esto liberará recursos valiosos durante las primeras etapas de la carga de la página

Compare your segments.

Is iOS slower than Android? Is the checkout route failing INP? Filter by device, route, and connection type.

Analyze Segments >>

  • Device filtering
  • Route Analysis
  • Connection Types
Aplaza los scripts hasta que sean necesariosCore Web Vitals Aplaza los scripts hasta que sean necesarios