Servir medios adaptativos usando Service Workers
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
| ECT | RTT Mínimo (ms) | Downlink Máximo (Kbps) | Explicación |
|---|---|---|---|
| slow‑2g | 2000 | 50 | La red es adecuada solo para transferencias pequeñas como páginas de solo texto. |
| 2g | 1400 | 70 | La red es adecuada para transferencias de imágenes pequeñas. |
| 3g | 270 | 700 | La red es adecuada para transferencias de activos grandes como imágenes de alta resolución, audio y vídeo SD. |
| 4g | 0 | ∞ | La red es adecuada para vídeo HD, vídeo en tiempo real, etc. |
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.

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.