Arquitectura de Aplicaciones Web Progresivas: Patrones de Service Worker en JavaScript | MLOG | MLOG

4. Solo Red (Network-Only)

La estrategia de solo red siempre obtiene los recursos de la red, omitiendo el caché por completo. Esta estrategia se utiliza cuando se necesita absolutamente la última versión de un recurso y no se desea el almacenamiento en caché.

Ejemplo:

            
self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request)
  );
});

            

5. Obsoleto Mientras se Revalida (Stale-While-Revalidate)

La estrategia de obsoleto mientras se revalida sirve el recurso almacenado en caché inmediatamente mientras que simultáneamente obtiene la última versión de la red. Una vez que la solicitud de red se completa, el caché se actualiza con la nueva versión. Esta estrategia proporciona una respuesta inicial rápida al tiempo que garantiza que el usuario finalmente reciba el contenido más actualizado. Es una estrategia útil para contenido no crítico que se beneficia de la velocidad sobre la frescura absoluta.

Ejemplo:

            
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        const fetchPromise = fetch(event.request).then(networkResponse => {
          caches.open('my-cache').then(cache => {
            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          });
        });
        return response || fetchPromise;
      })
  );
});

            

6. Caché y Luego Red (Cache, then Network)

Similar a stale-while-revalidate pero sin el retorno inmediato del recurso en caché. Primero comprueba el caché, y solo si el recurso está presente, la solicitud de red procederá en segundo plano para actualizar el caché.

Eligiendo la Estrategia de Caché Adecuada

La estrategia de caché óptima depende de los requisitos específicos de su aplicación. Considere factores como:

Al seleccionar cuidadosamente las estrategias de caché adecuadas, puede mejorar significativamente el rendimiento y la experiencia de usuario de su PWA, incluso en entornos sin conexión. Herramientas como Workbox ([https://developers.google.com/web/tools/workbox](https://developers.google.com/web/tools/workbox)) pueden simplificar la implementación de estas estrategias.

Sincronización en Segundo Plano: Manejando Mutaciones sin Conexión

La sincronización en segundo plano permite que su PWA realice tareas en segundo plano, incluso cuando el usuario está desconectado. Esto es particularmente útil para manejar envíos de formularios, actualizaciones de datos y otras operaciones que requieren conectividad de red. La API `BackgroundSyncManager` le permite registrar tareas que se ejecutarán cuando la red esté disponible.

Registrando una Tarea de Sincronización en Segundo Plano

Para registrar una tarea de sincronización en segundo plano, debe usar el método `register` del `BackgroundSyncManager`. Este método toma un nombre de etiqueta único como argumento. El nombre de la etiqueta identifica la tarea específica que se debe realizar.

Ejemplo:

            
self.addEventListener('sync', event => {
  if (event.tag === 'my-sync-task') {
    event.waitUntil(doSomeWork());
  }
});

            

Manejando el Evento de Sincronización (Sync)

Cuando el navegador detecta conectividad de red, despacha un evento `sync` al service worker. Puede escuchar este evento y realizar las acciones necesarias, como enviar datos al servidor.

Ejemplo:

            
async function doSomeWork() {
  // Recuperar datos de IndexedDB
  const data = await getDataFromIndexedDB();

  // Enviar datos al servidor
  try {
    const response = await fetch('/api/sync', {
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
        'Content-Type': 'application/json'
      }
    });

    if (response.ok) {
      // Limpiar los datos de IndexedDB
      await clearDataFromIndexedDB();
    } else {
      // Manejar errores
      console.error('La sincronización falló:', response.status);
      throw new Error('La sincronización falló');
    }
  } catch (error) {
    // Manejar errores de red
    console.error('Error de red:', error);
    throw error;
  }
}

            

Ejemplo: Envío de Formulario sin Conexión

Imagine un escenario en el que un usuario completa un formulario mientras está desconectado. El service worker puede almacenar los datos del formulario en IndexedDB y registrar una tarea de sincronización en segundo plano. Cuando la red esté disponible, el service worker recuperará los datos del formulario de IndexedDB y los enviará al servidor.

  1. El usuario llena el formulario y hace clic en enviar mientras está desconectado.
  2. Los datos del formulario se almacenan en IndexedDB.
  3. Se registra una tarea de sincronización en segundo plano con una etiqueta única (por ejemplo, `form-submission`).
  4. Cuando la red está disponible, se activa el evento `sync`.
  5. El service worker recupera los datos del formulario de IndexedDB y los envía al servidor.
  6. Si el envío es exitoso, los datos del formulario se eliminan de IndexedDB.

Notificaciones Push: Involucrando a los Usuarios con Actualizaciones Oportunas

Las notificaciones push permiten que su PWA envíe actualizaciones y mensajes oportunos a los usuarios, incluso cuando la aplicación no se está ejecutando activamente en el navegador. Esto puede mejorar significativamente la participación y retención de usuarios. La API Push y la API de Notificaciones trabajan juntas para entregar notificaciones push.

Suscripción a Notificaciones Push

Para recibir notificaciones push, los usuarios primero deben otorgar permiso a su PWA. Puede usar la API `PushManager` para suscribir a los usuarios a las notificaciones push.

Ejemplo:

            
navigator.serviceWorker.ready.then(registration => {
  registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: 'YOUR_PUBLIC_VAPID_KEY'
  })
  .then(subscription => {
    // Enviar detalles de la suscripción a tu servidor
    sendSubscriptionToServer(subscription);
  })
  .catch(error => {
    console.error('Fallo al suscribirse:', error);
  });
});

            

Importante: Reemplace `YOUR_PUBLIC_VAPID_KEY` con su clave VAPID (Identificación Voluntaria del Servidor de Aplicaciones) real. Las claves VAPID se utilizan para identificar su servidor de aplicaciones y garantizar que las notificaciones push se envíen de forma segura.

Manejando las Notificaciones Push

Cuando se recibe una notificación push, el service worker despacha un evento `push`. Puede escuchar este evento y mostrar la notificación al usuario.

Ejemplo:

            
self.addEventListener('push', event => {
  const payload = event.data ? event.data.text() : 'Sin contenido';

  event.waitUntil(
    self.registration.showNotification('Mi PWA', {
      body: payload,
      icon: 'icon.png'
    })
  );
});

            

Personalizando las Notificaciones Push

La API de Notificaciones le permite personalizar la apariencia y el comportamiento de las notificaciones push. Puede especificar el título, cuerpo, icono, insignia y otras opciones.

Ejemplo:

            
self.addEventListener('push', event => {
  const data = event.data.json();
  const title = data.title || 'Mi PWA';
  const options = {
    body: data.body || 'Sin mensaje',
    icon: data.icon || 'icon.png',
    badge: data.badge || 'badge.png',
    vibrate: [200, 100, 200],
    data: { // Datos personalizados a los que puedes acceder cuando el usuario hace clic en la notificación
      url: data.url || '/'
    },
    actions: [
      {action: 'explore', title: 'Explora este nuevo mundo',
        icon: 'images/checkmark.png'},
      {action: 'close', title: 'Cerrar',
        icon: 'images/xmark.png'},
    ]
  };

  event.waitUntil(self.registration.showNotification(title, options));
});


self.addEventListener('notificationclick', function(event) {
  event.notification.close();

  // Comprobar si el usuario hizo clic en una acción.
  if (event.action === 'explore') {
    clients.openWindow(event.notification.data.url);
  } else {
    // Acción por defecto: abrir la aplicación.
    clients.openWindow('/');
  }
});

            

Ejemplo: Alerta de Noticias

Una aplicación de noticias puede usar notificaciones push para alertar a los usuarios sobre noticias de última hora. Cuando se publica un nuevo artículo, el servidor envía una notificación push al dispositivo del usuario, mostrando un breve resumen del artículo. El usuario puede luego hacer clic en la notificación para abrir el artículo completo en la PWA.

Patrones Avanzados de Service Worker

1. Analíticas sin Conexión

Realice un seguimiento del comportamiento del usuario incluso cuando esté desconectado almacenando datos de análisis localmente y enviándolos al servidor cuando la red esté disponible. Esto se puede lograr usando IndexedDB y Background Sync.

2. Versionado y Actualización

Implemente una estrategia de versionado robusta para su service worker para garantizar que los usuarios siempre reciban las últimas actualizaciones sin interrumpir su experiencia. Utilice técnicas de 'cache busting' para invalidar los recursos antiguos en caché.

3. Service Workers Modulares

Organice el código de su service worker en módulos para mejorar la mantenibilidad y la legibilidad. Use módulos de JavaScript (ESM) o un empaquetador de módulos como Webpack o Rollup.

4. Almacenamiento en Caché Dinámico

Almacene en caché los recursos dinámicamente según las interacciones del usuario y los patrones de uso. Esto puede ayudar a optimizar el tamaño del caché y mejorar el rendimiento.

Mejores Prácticas para el Desarrollo de Service Workers

Conclusión

Los service workers de JavaScript son herramientas poderosas para construir PWAs robustas, de alto rendimiento y atractivas. Al comprender el ciclo de vida del service worker e implementar estrategias de almacenamiento en caché adecuadas, sincronización en segundo plano y notificaciones push, puede crear experiencias de usuario excepcionales, incluso en entornos sin conexión. Este artículo ha explorado patrones clave de service worker y mejores prácticas para guiarlo en la construcción de PWAs exitosas para una audiencia global. A medida que la web continúa evolucionando, los service workers desempeñarán un papel cada vez más importante en la configuración del futuro del desarrollo web.

Recuerde adaptar estos patrones a los requisitos específicos de su aplicación y siempre priorice la experiencia del usuario. Al adoptar el poder de los service workers, puede crear PWAs que no solo sean funcionales, sino también agradables de usar, independientemente de la ubicación o la conexión de red del usuario.

Recursos Adicionales: