VOLVER

Servir medios adaptativos usando Service Workers

4 min de lectura

Haciendo pair con @Ester Martí

Visitar un sitio web con una conexión de red lenta tarda una eternidad en cargar, haciendo la experiencia dolorosa o imposible.

Los desarrolladores web a menudo olvidan el rendimiento de carga mientras añaden características llamativas. Pero los usuarios probablemente navegan en dispositivos móviles de gama media o baja con conexiones 3G como máximo--no el último MacBook Pro con fibra gigabit.

En 2018, el 52.2% de todas las páginas web globales se sirvieron a teléfonos móviles.

El rendimiento importa, y la entrega de medios consume más recursos. Adaptaremos la entrega de medios basada en la conexión de red usando la API de Información de Red. Esto mejora un experimento que construí con @Eduardo Aquiles como componente de React, similar al artículo de Max Böck sobre componentes conscientes de la conexión--pero usando service workers.

La API de Información de Red

La API de Información de Red es un borrador de especificación que expone información de conexión del dispositivo a JavaScript.

La interfaz proporciona varios atributos de red. Los más relevantes aquí:

  • type: El tipo de conexión que el agente de usuario está utilizando. (p.ej. ‘wifi’, ‘cellular’, ‘ethernet’, etc.)
  • effectiveType El tipo de conexión efectiva que se determina utilizando una combinación de rtt y downlink observados recientemente. (ver tabla)
  • saveData Indica cuando el usuario solicitó un uso reducido de datos.

valores de effectiveType

ECTRTT Mínimo (ms)Downlink Máximo (Kbps)Explicación
slow‑2g200050 La red es adecuada solo para transferencias pequeñas como páginas de solo texto.
2g140070 La red es adecuada para transferencias de imágenes pequeñas.
3g270700 La red es adecuada para transferencias de activos grandes como imágenes de alta resolución, audio y vídeo SD.
4g0 La red es adecuada para vídeo HD, vídeo en tiempo real, etc.
Tabla de{" "} tipos de conexión efectiva (ECT)

Soporte del navegador

La API carece de soporte completo del navegador pero funciona en los navegadores móviles más populares--donde esta técnica tiene mayor impacto.

Soporte del navegador para la API de Información de Red

De hecho, el 70% de los usuarios móviles tienen esta API habilitada en su dispositivo.

Servir Medios Adaptativos

Serviremos diferentes recursos multimedia basados en effectiveType. "Diferentes medios" podría significar cambiar entre vídeo HD, imagen HD o imagen de baja calidad, como sugiere Addy Osmani.

Este ejemplo usa diferentes niveles de compresión para la misma imagen.

Primero, obtén la calidad adecuada basada en las condiciones de red:

function getMediaQuality() {
const connection =
navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection;
if (!connection) {
return "medium";
}
switch (connection.effectiveType) {
case "slow-2g":
case "2g":
return "low";
case "3g":
return "medium";
case "4g":
return "high";
default:
return "low";
}
}

Imagina un servidor de imágenes que acepta un parámetro quality (low, medium o high). Establece la calidad en el atributo src:

<img src="http://images.magarcia.io/cute_cat?quality=low" alt="Gato lindo" />
const images = document.querySelectorAll("img");
images.forEach((img) => {
img.src = img.src.replace("low", getMediaQuality());
});

La calidad por defecto es low, así que los dispositivos cargan primero la imagen de baja calidad, luego mejoran en conexiones rápidas.

El JavaScript obtiene todas las imágenes y reemplaza el parámetro de calidad según getMediaQuality. Para calidad low, no hay peticiones adicionales. Para medium o high, ocurren dos peticiones: una para low al analizar la etiqueta img, otra para mejor calidad cuando ejecuta JavaScript.

Esto mejora los tiempos de carga en redes lentas pero duplica las peticiones en conexiones rápidas, consumiendo datos extra.

Usando Service Workers

Los service workers resuelven el problema de doble petición interceptando las peticiones del navegador y reemplazándolas con la calidad apropiada.

Primero, registra el service worker:

if ("serviceWorker" in navigator) {
window.addEventListener("load", function () {
navigator.serviceWorker.register("/sw.js").then(
function (registration) {
console.log(
"Registro de ServiceWorker exitoso con alcance: ",
registration.scope,
);
},
function (err) {
console.log("Registro de ServiceWorker fallido: ", err);
},
);
});
}

Añade un listener del evento fetch que añade el parámetro de calidad correcto a las peticiones de imágenes:

self.addEventListener("fetch", function (event) {
if (/\.jpg$|.png$|.webp$/.test(event.request.url)) {
const url = event.request.url + `?quality=${getMediaQuality()}`;
event.respondWith(fetch(url));
}
});

Ahora omite el parámetro de calidad de las etiquetas img--el service worker lo gestiona:

<img src=“http://images.magarcia.io/cute_cat” alt=“Gato lindo”/>

El código

Encuentra el código completo y más limpio en este repositorio de GitHub.

Lectura Adicional