Las secuencias de comandos de terceros afectan el rendimiento, por lo que es importante auditarlas periódicamente y usar técnicas eficientes para cargarlas. En este codelab, se muestra cómo optimizar la carga de recursos de terceros. Se abordan las siguientes técnicas:
Cómo posponer la carga de la secuencia de comandos
Carga diferida de recursos no críticos
Realiza una conexión previa a los orígenes necesarios
La app de ejemplo incluida presenta una página web simple con tres funciones que provienen de fuentes externas:
Una incorporación de video
Una biblioteca de visualización de datos para renderizar un gráfico de líneas
Un widget para compartir contenido en redes sociales
![Captura de pantalla de la página con recursos de terceros destacados.](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-the-page-thi-cc10c15b4c9aa.png?authuser=3&hl=es-419)
Comenzarás por medir el rendimiento de la app y, luego, aplicarás cada técnica para mejorar diferentes aspectos de su rendimiento.
Cómo medir el rendimiento
Primero, abre la app de ejemplo en la vista de pantalla completa:
- Haz clic en Remix para editar para que el proyecto se pueda editar.
- Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona
Pantalla completa
Ejecuta una auditoría de rendimiento Lighthouse en la página para establecer un rendimiento de referencia:
- Presiona `Control + Mayúsculas + J` (o `Command + Option + J` en Mac) para abrir Herramientas para desarrolladores.
- Haz clic en la pestaña Lighthouse.
- Haz clic en Dispositivos móviles.
- Selecciona la casilla de verificación Rendimiento. (Puedes borrar el resto de las casillas de verificación en la sección Auditorías).
- Haz clic en Simulación rápida de 3G, 4x Slowdown de CPU.
- Selecciona la casilla de verificación Liberar espacio de almacenamiento.
- Haz clic en Ejecutar auditorías.
Cuando ejecutas una auditoría en tu máquina, los resultados exactos pueden variar, pero deberías notar que el tiempo de First Contentful Paint (FCP) es bastante alto y que Lighthouse sugiere dos oportunidades para investigar: Eliminar los recursos que bloquean la renderización y Preconectar a los orígenes requeridos. (Incluso si todas las métricas están en verde, las optimizaciones producirán mejoras de todas formas).
![Captura de pantalla de la auditoría de Lighthouse que muestra un FCP de 2.4 segundos y dos oportunidades: Elimina los recursos que bloquean la renderización y la opción Preconnect para los orígenes requeridos.](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-lighthouse-au-d025b777206eb.png?authuser=3&hl=es-419)
Difiere el código JavaScript de terceros
En la auditoría Elimina los recursos que bloquean el procesamiento, se identificó que puedes ahorrar tiempo si aplazas una secuencia de comandos proveniente de d3js.org:
![Captura de pantalla de la auditoría de Elimina los recursos que bloquean la renderización con la secuencia de comandos d3.v3.min.js destacada.](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-eliminate-ren-e12e8b7ae1ab3.png?authuser=3&hl=es-419)
D3.js es una biblioteca de JavaScript para crear visualizaciones de datos. El archivo script.js
de la app de ejemplo usa funciones de utilidad de D3 para crear el gráfico de líneas SVG y agregarlo a la página. Aquí, el orden de las operaciones es importante: script.js
debe ejecutarse después de que se analiza el documento y se carga la biblioteca de D3, por lo que se incluye justo antes de la etiqueta de cierre </body>
en index.html
.
Sin embargo, la secuencia de comandos de D3 está incluida en el <head>
de la página, que bloquea el análisis del documento resto:
![Captura de pantalla de index.html con la etiqueta script destacada en el encabezado.](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-indexhtml-h-4a8c4790995c8.png?authuser=3&hl=es-419)
Dos atributos mágicos pueden desbloquear el analizador cuando se agregan a la etiqueta de la secuencia de comandos:
async
garantiza que las secuencias de comandos se descarguen en segundo plano y se ejecuten en la primera oportunidad después de que finalicen la descarga.defer
garantiza que las secuencias de comandos se descarguen en segundo plano y se ejecuten después de que el análisis esté completamente terminado.
Dado que este gráfico no es realmente crítico para la página general y lo más probable es que aparezca en la mitad inferior de la página, usa defer
para asegurarte de que no haya bloqueado el analizador.
Paso 1: Carga la secuencia de comandos de forma asíncrona con el atributo defer
En la línea 17 de index.html
, agrega el atributo defer
al elemento <script>
:
<script src="https://d3js.org/d3.v3.min.js" defer></script>
Paso 2: Asegúrate de que las operaciones tengan el orden correcto
Ahora que D3 se aplaza, script.js
se ejecutará antes de que D3 esté lista, lo que generará un error.
Las secuencias de comandos con el atributo defer
se ejecutan en el orden en que se especificaron. Para asegurarte de que script.js
se ejecute después de que D3 esté listo, agrega defer
y muévelo hasta la <head>
del documento, justo después del elemento <script>
de D3. Ya no bloqueará el analizador, y la descarga comenzará antes.
<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>
Recursos de terceros de carga diferida
Todos los recursos que se encuentran en la mitad inferior de la página son buenos candidatos para la carga diferida.
La aplicación de ejemplo tiene un video de YouTube incorporado en un iframe. Para ver cuántas solicitudes realiza la página y cuáles provienen del iframe de YouTube incorporado, haz lo siguiente:
- Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona
Pantalla completa
- Presiona `Control + Mayúsculas + J` (o `Command + Option + J` en Mac) para abrir Herramientas para desarrolladores.
- Haga clic en la pestaña Red.
- Selecciona la casilla de verificación Inhabilitar caché.
- Selecciona 3G rápida en el menú desplegable Regulación.
- Vuelve a cargar la página.
El panel Red revela que la página realizó un total de 28 solicitudes y transfirió casi 1 MB de recursos comprimidos.
Para identificar las solicitudes que realizó el iframe
de YouTube, busca el ID de video 6lfaiXM6waw
en la columna Initiator. Para agrupar todas las solicitudes por dominio, haz lo siguiente:
En el panel Red, haz clic con el botón derecho en el título de una columna.
En el menú desplegable, selecciona la columna Dominios.
Para ordenar las solicitudes por dominio, haz clic en el título de la columna Dominios.
El nuevo orden revela que hay solicitudes adicionales a Google Domains. En total, el iframe de YouTube realiza 14 solicitudes de secuencias de comandos, hojas de estilo, imágenes y fuentes. Pero, a menos que los usuarios se desplacen hacia abajo para reproducir el video, no necesitan todos esos recursos.
Si esperas la carga diferida del video hasta que un usuario se desplace hacia abajo a esa sección de la página, reduces la cantidad de solicitudes que la página realiza inicialmente. Este enfoque ahorra a los usuarios y acelera la carga inicial.
Una forma de implementar la carga diferida es usar Intersection Observer, una API del navegador que te notifica cuando un elemento entra al viewport del navegador o sale de él.
Paso 1: Evita que el video se cargue inicialmente
Para realizar una carga diferida en el iframe de video, primero debes evitar que se cargue de la manera habitual. Para ello, reemplaza el atributo src
por el atributo data-src
para especificar la URL del video:
<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
data-src
es un atributo de datos que te permite almacenar información adicional en elementos HTML estándar. Se puede asignar cualquier nombre a un atributo de datos, siempre que comience con "data-".
Un iframe sin un src
simplemente no se carga.
Paso 2: Usa Intersection Observer para realizar una carga diferida en el video
Para cargar un video cuando un usuario se desplaza hasta él, debes saber cuándo sucede. Ahí es donde entra en juego la API de Intersection Observer. La API de Intersection Observer te permite registrar una función de devolución de llamada que se ejecuta cada vez que un elemento que deseas rastrear entra en el viewport o sale de él.
Para comenzar, crea un archivo nuevo y asígnale el nombre lazy-load.js
:
- Haz clic en Archivo nuevo y asígnale un nombre.
- Haz clic en Agregar este archivo.
Agrega la etiqueta de secuencia de comandos al encabezado del documento:
<script src="/lazy-load.js" defer></script>
En lazy-load.js
, crea un nuevo elemento IntersectionObserver
y pásale una función de devolución de llamada para que se ejecute:
// create a new Intersection Observer
let observer = new IntersectionObserver(callback);
Ahora, pásale a observer
un elemento de destino para mirar (en este caso, el iframe de video). Para ello, pásalo como argumento en el método observe
:
// the element that you want to watch
const element = document.querySelector('iframe');
// register the element with the observe method
observer.observe(element);
callback
recibe una lista de objetos IntersectionObserverEntry
y el objeto IntersectionObserver
en sí. Cada entrada contiene un elemento target
y propiedades que describen sus dimensiones, su posición, la hora en que ingresó al viewport y mucho más. Una de las propiedades de IntersectionObserverEntry
es isIntersecting
, un valor booleano que es igual a true
cuando el elemento ingresa al viewport.
En este ejemplo, target
es iframe
. isIntersecting
es igual a true
cuando target
ingresa al viewport. Para ver esto en acción, reemplaza callback
por la siguiente función:
let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(entry => {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
- Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona
Pantalla completa
- Presiona `Control + Mayúsculas + J` (o `Command + Option + J` en Mac) para abrir Herramientas para desarrolladores.
- Haz clic en la pestaña Consola.
Intenta desplazarte hacia arriba y hacia abajo. Deberías ver el cambio de isIntersecting
y el elemento de destino registrado en la consola.
Para cargar el video cuando el usuario se desplaza a su posición, usa isIntersecting
como condición para ejecutar una función loadElement
, que obtiene el valor del data-src
del elemento iframe
y lo establece como el atributo src
del elemento iframe
. Ese reemplazo activa la carga del video. Luego, una vez que se cargue el video, llama al método unobserve
en observer
para dejar de mirar el elemento de destino:
let observer = new IntersectionObserver(function (entries, observer) {
entries.forEach(entry => {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
if (entry.isIntersecting) {
// do this when the element enters the viewport
loadElement(entry.target);
// stop watching
observer.unobserve(entry.target);
}
});
});
function loadElement(element) {
const src = element.getAttribute('data-src');
element.src = src;
}
Paso 3: Vuelve a evaluar el rendimiento
Para ver cómo cambiaron el tamaño y la cantidad de recursos, abre el panel Red de Herramientas para desarrolladores y vuelve a cargar la página. El panel Red revela que la página realizó 14 solicitudes y solo 260 KB. Es una mejora significativa.
Ahora, desplázate hacia abajo en la página y consulta el panel Red. Cuando llegues al video, deberías ver que la página activa solicitudes adicionales.
Establece una conexión previa en los orígenes necesarios
Pospusiste JavaScript no fundamental y cargaste de forma diferida las solicitudes de YouTube, por lo que es momento de optimizar el contenido restante de terceros.
Agregar el atributo rel=preconnect
a un vínculo le indica al navegador que establezca una conexión con un dominio antes de que se realice la solicitud de ese recurso. Este atributo se usa mejor en orígenes que proporcionan recursos que sabes que la página necesita.
La auditoría de Lighthouse que ejecutaste en el primer paso sugerido en Preconectar a los orígenes requeridos, que puedes ahorrar alrededor de 400 ms si establecis conexiones anticipadas constaticxx.facebook.com y youtube.com:
Dado que el video de YouTube ahora se carga de forma diferida, solo se deja estáticaxx.facebook.com, la fuente del widget para compartir contenido en redes sociales. Establecer una conexión anticipada a este dominio es tan simple como agregar una etiqueta <link>
al <head>
del documento:
<link rel="preconnect" href="https://staticxx.facebook.com">
Volver a evaluar el rendimiento
Este es el estado de la página después de la optimización. Sigue los pasos de la sección Mide el rendimiento del codelab para ejecutar otra auditoría de Lighthouse.