¿Tratando de averiguar qué es un trabajador de servicio? No estás solo!
Un Service Worker es un script que se ejecuta en segundo plano, en un hilo separado de la UI del navegador. El caché del Service worker hace posible que un sitio web funcione sin conexión. Son la potencia técnica que eleva un sitio web a una aplicación web progresiva. Permiten una profunda integración de la plataforma, como el almacenamiento en caché enriquecido, las notificaciones push y la sincronización en segundo plano.
Los service workers están diseñados para ser una plataforma extensible, actualmente se están planeando características adicionales.
No pueden acceder al DOM, pero pueden interceptar todas las peticiones de red. Esto permite a los desarrolladores la oportunidad de controlar cómo se manejan las solicitudes, proporcionando una forma rica de hacer que los sitios web funcionen fuera de línea.
Los trabajadores de servicio se han llamado un cambio de juego para la web. No creo que sea una simple exageración, porque permiten muchas capacidades muy necesarias y hacen que la arquitectura principal que he utilizado durante años sea nativa.
Los Service Workers suenan increíbles!
Esta es la tecnología clave o API web moderna detrás de las Aplicaciones Web Progresivas. Sin un service worker un sitio web es solo un sitio web, añade un service worker y ya tienes una aplicación.
Hay algunas características clave sobre los service workers que debes entender:
- Un Service Worker es un archivo JavaScript
- Se ejecutan en un hilo separado de la UI
- No pueden acceder al DOM directamente
- Hay un ciclo de vida o una serie de eventos por los que fluye un service worker para activarse, que se explica más adelante
- Sólo están vivos mientras se usan, por lo que no hay carga de batería
- Están aislados en el origen o dominio con el que están registrados
- Los service workers requieren HTTPS
- Pueden enviar mensajes hacia y desde la UI
- No requieren una página web abierta para funcionar
- Son compatibles con los principales navegadores, incluyendo Safari de iOS
- Son similares a los Web Workers, pero mejores en muchos aspectos
- ¿Cómo funcionan los Service Workers?
- Extensibilidad de los Service Workers
- Ciclo de vida de los Service Workers
- ¿Cuánto tiempo duran los Service Workers?
- ¿Cómo comprobar si un Service Worker está registrado?
- ¿Cómo anulo el registro de un Service Worker
- Caché de Service Worker
- Cómo actualizo mi caché de Service Worker
- ¿Qué navegadores admiten Service Workers?
- ¿Cuál es la diferencia entre un Service Worker y un Web Worker
- Qué no puede hacer un Service Worker
¿Cómo funcionan los Service Workers?
Un Service Worker se sitúa entre el navegador y la red, actuando como un servidor proxy, manejando una colección de tareas no centradas en la interfaz de usuario. Son impulsados por eventos y viven fuera del proceso del navegador, lo que les permite trabajar sin una sesión activa del navegador. El service worker es un script que se ejecuta en un hilo, separado de la UI. Esto permite al service worker realizar tareas no relacionadas con la UI, haciendo que un sitio web funcione mejor.
Los service workers terminan cuando no están en uso y se restauran cuando son necesarios, esto evita que agoten la CPU y las baterías. Actúan como un proxy de red programable, o intermediario entre el navegador y la red, permitiendo a los desarrolladores diseñar cómo se manejan las solicitudes de red.
El primer poder que un trabajador de servicio aporta a un sitio web es la capacidad de habilitar capacidades fuera de línea con control granular. Esto se hace con una rica API de almacenamiento en caché e interceptando todas las solicitudes de red antes de que salgan.
El almacenamiento en caché no sólo permite experiencias sin conexión, los sitios web pueden cargar al instante cuando se recuperan de la caché. El almacenamiento en caché del trabajador de servicios hace que la red sea una mejora progresiva, o que no sea necesaria para que el sitio sea utilizable.
Extensibilidad del trabajador de servicios
Una característica subestimada del trabajador de servicios es su extensibilidad Los trabajadores de servicios están diseñados para ser la columna vertebral que soporta la funcionalidad adicional. Las dos primeras características que se están lanzando en los navegadores son las notificaciones push nativas y la sincronización en segundo plano. Actualmente se están debatiendo más APIs nuevas que deberían empezar a aparecer en los navegadores en un futuro próximo.
Los service workers viven en su propio hilo y no tienen acceso al DOM. También tienen su propio ámbito global, al que se hace referencia usando el objeto ‘self’.
También requieren que un sitio se sirva usando HTTPS. Este requisito se debe a las potentes características que ofrecen los service workers. HTTPS previene muchos ataques comunes. Hoy en día todos los sitios deberían ser servidos usando HTTPS ya que se han eliminado las barreras para su implementación y la cantidad mínima de seguridad que ofrecen.
También son asíncronos. Esto significa que todas las APIs soportan promesas. Esto también significa que ciertas APIs y funciones no son accesibles en los service workers. El más notable es localStorage. En su lugar, los datos deben ser almacenados utilizando IndexedDB.
Ciclo de vida de los service workers
Antes de sumergirse en estas grandes características de los service workers los desarrolladores necesitan entender el ciclo de vida.
Un service worker debe ser registrado por un sitio web. Debido a que algunos navegadores todavía no soportan los service workers se debe realizar una comprobación de características antes de registrar un service worker. Esto se hace comprobando la presencia de ‘serviceWorker’ en navigator.
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(function(registration) { // Registration was successful }) .catch(function(err) { // registration failed :( }); }
Para registrar el service worker llama a navigator.serviceWorker.register. Pasa la ruta del service worker. La función register devuelve una promesa.
Si tiene éxito la promesa devuelve una referencia al objeto de registro del service worker. A partir de ahí se pueden realizar tareas específicas de la UI según sea necesario.
Eventos estándar del service worker
- install
- activate
- fetch
- push (no soportado por Safari)
- sync (no soportado por la mayoría de los navegadores todavía)
Cuando se registra un service worker el evento «install». En este evento la tarea más común a realizar se llama pre-caché.
El pre-caché es donde se hace una lista predefinida de archivos de activos necesarios para formar una página o sitio, y se añaden a la caché antes de ser solicitados. Esto aprovecha la caché del service worker para persistir estas respuestas.
self.addEventListener("install", event => { event.waitUntil( caches.open(preCacheName) .then(function (cache) { return cache.addAll(precache_urls); }) ); });
El evento de instalación sólo se dispara una vez en la vida de un service worker. El evento no se disparará de nuevo hasta que el trabajador de servicio se actualice.
El siguiente evento que se dispara como parte del ciclo de vida del registro es ‘activate’. Cuando se instala un service worker no se activa inmediatamente. La secuencia natural es que un nuevo service worker espere hasta que se cierren todos los ‘clientes’ del service worker.
La razón por la que los service workers están diseñados para no activarse inmediatamente es para evitar que rompan la experiencia del usuario.
La función skipWaiting fuerza a un service worker en espera a activarse. Esto sólo debe emplearse cuando se está seguro de que el nuevo trabajador de servicio no romperá ningún cliente existente.
self.skipWaiting();
Una vez que el trabajador de servicio se activa se dispara el evento ‘activate’.
self.addEventListener("activate", event => { //on activate event.waitUntil(clients.claim()); });
Este evento se utiliza comúnmente para realizar cualquier tarea de limpieza o migración. Por ejemplo, la eliminación de las memorias caché heredadas que podrían entrar en conflicto con las nuevas memorias caché de los trabajadores de servicio.
¿Cuánto tiempo duran los trabajadores de servicio?
No hay una regla fija sobre el tiempo que un navegador mantiene un trabajador de servicio en funcionamiento. Internamente, el motor del navegador utilizará un conjunto de heurísticas para determinar cuándo terminar el proceso de trabajador de servicio.
En general, si una página web está inactiva, el proceso se cerrará después de un minuto o dos, tal vez tan pronto como 30 segundos.
La realidad es que el tiempo exacto dependerá del hardware, los patrones de uso, etc.
La buena noticia es que se tarda un puñado de milisegundos en encender un service worker. Es tan rápido que no notarás ninguna latencia. Tampoco es necesario programar nada especial para hacer frente a un escenario sin el trabajador de servicio, su sitio simplemente funcionará. La magia de la mejora progresiva.
¿Cómo puedo comprobar si un Service Worker está registrado?
Hay varias formas de comprobar si un service worker está registrado. La más fácil es llamar al método serviceworkers.getRegistrations.
navigator.serviceWorker.getRegistrations().then(registrations => { console.log(registrations); });
Este es un código que puede añadir a su script de páginas para registrar el registro para el soporte técnico o la depuración del desarrollador.
El método ‘getRegistrations’ devuelve un array de todos los service workers registrados bajo el ámbito o sitio web actual.
Si sólo está registrando el registro en la consola sería mejor ver la pestaña ‘Aplicación’ de Dev Tools. Tiene un subpanel que muestra un visual del trabajador de servicio registrado del origen. También puede desencadenar eventos de sincronización en segundo plano y probar las notificaciones push.
También puede eliminar el trabajador de servicio, forzar una actualización y otras gestiones generales que ayudan al desarrollo.
El verdadero valor que ofrece getRegistrations es para una especie de función de soporte de puerta trasera. Todos sabemos lo que es tratar de ayudar a alguien de forma remota y no se puede acceder a la DevTools para realmente solucionar el problema. A veces usted querrá algún tipo de página de soporte visual o modal para proporcionar información sobre el estado de la aplicación.
El consumidor medio no sabrá cómo acceder al panel de la consola DevTools. En su lugar, puede crear una interfaz de usuario dentro de la aplicación para hacerse eco de las propiedades del objeto de registro del trabajador de servicio.
¿Cómo puedo anular el registro de un trabajador de servicio
Con suerte, no se encontrará con un escenario en el que su código de trabajador de servicio haya creado un error de experiencia de usuario. En caso de que lo haga, hay algunas cosas que puede hacer para eliminar o anular el registro de un service worker.
La mayoría de los escenarios en los que necesita eliminar un service worker será cuando esté desarrollando la aplicación. En este caso puedes utilizar las DevTools para eliminar o borrar el service worker.
Si necesita eliminar o borrar un service worker desplegado se vuelve un poco más complicado. Hay formas programáticas para sacarte del apuro.
Lee más sobre las técnicas de eliminación.
Caché del service worker
La especificación del service worker incluye capacidades nativas de caché. Esto reemplaza al tradicional appCache que ha causado muchos problemas de gestión desde su creación. El almacenamiento en caché del service worker es mucho más manejable.
La API de caché proporciona una capa de persistencia que almacena las respuestas de red que pueden ser consultadas por la solicitud correspondiente.
La clave para utilizar el almacenamiento en caché del service worker es el evento ‘fetch’ del service worker. Este evento se dispara para cada petición de red permitiéndole interceptar la petición y comprobar si la respuesta ha sido almacenada en la caché antes de que vaya a la red.
Al acceder a los activos en la caché local puede renunciar a las costosas peticiones de red. Esto significa que el sitio puede funcionar cuando no hay red, fuera de línea, o mala conectividad de red, barras bajas o falsa conectividad celular (conocida como LiFi).
self.addEventListener("fetch", event => { event.respondWith( fetchFromCache(event) .catch(() => fetch(request) .then(response => addToCache(cacheKey, request, response)) .catch(() => offlineResponse(resourceType, opts)) ) ); });
En el ejemplo anterior el código comprueba si una respuesta ha sido previamente cacheada. Si es así, se devuelve la respuesta en caché. Si no la solicitud se pasa a lo largo de la red.
Cuando la solicitud devuelve la respuesta se almacena en caché y se devuelve a la UI.
Si la red falla la lógica cae de nuevo a una respuesta fuera de línea.
Hay un montón de partes móviles que se utilizan en el código de ejemplo. Proporcionaré más detalles en un artículo de seguimiento.
¿Cómo actualizo mi caché de trabajador de servicio
Una idea errónea común es que una vez que se almacena en caché una solicitud de red se almacena para la eternidad. Este no es el caso. Usted tiene el control completo sobre cuándo y cómo se invalida y actualiza la caché.
Este es un tema muy complejo e involucrado. Creo que personalmente puedo detallar unas 3 docenas de estrategias de caché, todas implican una forma de gestionar la invalidación de la caché o su actualización.
Creo que la clave de la invalidación es determinar o bien un valor de tiempo de invalidación (time to live), un manifiesto o un proceso de actualización en segundo plano. En este último se puede hacer una petición HEAD para ver si se ha hecho una actualización en el servidor comparando el valor de la última actualización de la cabecera con el tiempo en que la respuesta fue almacenada en la caché.
No hay una respuesta única para cada aplicación. Tendrá que planificar su estrategia y estar preparado para ajustarse a medida que vea cómo se utiliza su aplicación.
¿Qué navegadores soportan Service Workers?
Todos los navegadores modernos soportan Service Workers, al menos el almacenamiento en caché. Chrome, FireFox y Edge soportan notificaciones push nativas y Chrome y Edge tienen soporte de sincronización en segundo plano.
Esto significa que las características principales de la PWA están disponibles en todos los dispositivos y navegadores. El push y la sincronización en segundo plano son mejoras.
Hemos construido varias Progressive Web Apps que requerían sofisticadas estrategias de caché sin conexión para permitir que las aplicaciones funcionaran sin conexión, incluso en iOS. Estas aplicaciones requieren que todas las peticiones, incluso las acciones POST, PUT y DELETE se almacenen en caché en una cola. Hicimos que estas aplicaciones se sincronizaran incluso en iOS cuando se sabía que las conexiones estaban disponibles.
¿Cuál es la diferencia entre un Service Worker y un Web Worker
Los service workers y los web workers son herramientas similares. Ambos ejecutan procesos en un hilo separado de la interfaz de usuario. La verdadera diferencia radica en el contexto de uso real.
Ninguno tiene acceso al objeto DOM o ventana. Son mejores para tareas de nivel medio o largas e intensivas en procesos.
Los web workers sólo se ejecutan cuando una página web está abierta y una tarea es desencadenada desde un script en la página.
Un service worker también puede ejecutarse cuando una página está abierta, pero también puede ser desencadenado por un evento de la plataforma como una notificación push. Una página web no tiene que estar abierta para que un service worker se ejecute.
Los service workers también actúan como un proxy entre la red y la interfaz de usuario. Si se está utilizando una página (el escenario más común) todas las peticiones de red HTTPS pasan a través del service worker como aprendiste en la sección de caché.
La comunicación entre la UI y ambos workers se realiza utilizando el método postMessage y el evento message. Si has realizado alguna programación multihilo este modelo te resultará muy familiar.
Lo que no puede hacer un service worker
Los service workers no pueden acceder al objeto Window
El objeto Window se ejecuta en el hilo de la UI, separado del hilo del service worker. Esto significa que un service worker no puede manipular directamente los elementos del DOM. El trabajador de servicios y la ventana pueden comunicarse a través del método postMessage. Esto permite que los mensajes se pasen de un lado a otro. Necesitarás tener lógica en cada lado para procesar los mensajes y desencadenar diferentes flujos de trabajo.
Los Service Workers requieren HTTPS
Debido a que los Service Workers tienen tanto poder sólo están habilitados si la página se sirve usando HTTPS. Esto asegura un nivel de seguridad para permitir que el service worker haga las cosas para las que está diseñado.
Con HTTP el service worker sería susceptible de ataques de man in the middle. Los desarrolladores pueden trabajar en localhost, lo que nos evita instalar un certificado TLS local.
En otras palabras, la respuesta a si un service worker funciona sobre HTTP es no. El sitio seguirá renderizando, pero el service worker no se registra y no se ejecuta.
Sólo son asíncronos
Los service workers son asíncronos, lo que significa que usan y dependen de Promises y APIs que usan Promises. Esto significa que las APIs sincrónicas como XHR y localStorage no están disponibles para un service worker. No temas, puedes utilizar la API Fetch (que sustituyó a XHR) y IndexedDB. La mayoría de las APIs que no interactúan directamente con el objeto ventana son accesibles en un service worker.