Una Comparación de los Web Workers

Rate this content
Bookmark

Los navegadores modernos vienen equipados con tres tipos de Web Workers: Dedicados, Compartidos y Service Workers. Si bien cada uno ofrece la capacidad de ejecutar JavaScript en un hilo separado, sus diferentes APIs y capacidades significan que cualquier tarea dada generalmente tiene un worker ideal. Aprende los beneficios de cada worker y cómo elegir el adecuado.

25 min
18 Feb, 2022

Video Summary and Transcription

Esta Charla compara los web workers, incluyendo los workers dedicados, los workers compartidos y los service workers. Los web workers proporcionan capacidades de multithreading y utilizan memoria compartida para un mayor rendimiento. Los workers dedicados tienen un padre y pueden ejecutarse en un hilo separado. Los workers compartidos pueden tener múltiples padres y son útiles para la comunicación entre diferentes ventanas. Los service workers pueden interceptar y proxy las solicitudes realizadas desde una página web y son útiles para almacenar en caché los activos de red y construir aplicaciones web progresivas.

Available in English

1. Introducción a los Web Workers

Short description:

Hola, soy Thomas Hunter y esta charla es una comparación de los web workers. Hoy vamos a hablar de los dedicated workers, shared workers y service workers. JavaScript es de un solo hilo, pero los web workers proporcionan capacidades de multihilo. Los web workers utilizan memoria compartida para un mayor rendimiento y multihilo. Cada entorno de JavaScript está aislado, con sus propias variables y globales. Los web workers no pueden acceder al DOM, pero se puede utilizar memoria compartida para acceder a los datos.

Hola, soy Thomas Hunter y esta charla es una comparación de los web workers. El contenido de esta charla está adaptado de un libro que publiqué recientemente, JavaScript Multihilo. Si quieres más información sobre el libro, no dudes en seguir la URL de bitly que se encuentra en la parte inferior de la pantalla.

Muy bien. Así que hoy vamos a hablar de tres temas diferentes. El primero son los dedicated workers. El segundo son los shared workers. Y el tercero son los service workers. Cada uno de estos workers es un tipo de web worker. Pero primero, voy a hablar de algunos conceptos básicos. Así que, primero, el concepto de multihilo en JavaScript. Una cosa a tener en cuenta es que es la naturaleza de JavaScript y su ecosistema ser de un solo hilo. Durante mucho tiempo, no existían realmente capacidades de multihilo en JavaScript. Podías hacer algo parecido utilizando el envío de mensajes básico, utilizando iframes. Pero no era exactamente la solución más limpia. Sin embargo, ahora tenemos los web workers disponibles. Y con eso viene una característica llamada memoria compartida, que permite un mayor rendimiento y multihilo que simplemente utilizar el envío de mensajes. Esta presentación se va a centrar en el uso de estos web workers con fines de multihilo ya que está relacionado con el libro. Muy bien. Otro concepto básico es, bueno, ¿qué es un entorno de JavaScript? Bueno, un entorno de JavaScript es una colección aislada de variables, globales, cosas como, ya sabes, el objeto capital O van a ser diferentes en estos entornos separados, las cadenas de prototipos, ya sabes, a qué objetos terminan apuntando son diferentes en estos diferentes entornos. Cada entorno adicional va a tener un cierto costo adicional para iniciarse y en Node es más fácil de medir. En mis experimentos se consumían alrededor de seis megabytes de memoria por cada nueva instancia de hilo de trabajo. En un navegador vas a tener un poco más de costo adicional. Los web workers van a tener un cierto costo adicional de memoria y luego si tienes páginas adicionales habrá aún más costo adicional ya que hay diferentes documentos y rectángulos que deben renderizarse. Estas instancias de objetos que se crean en estos diferentes entornos nunca pueden ser verdaderamente compartidas entre entornos. Sin embargo, puedes serializar estos objetos, puedes clonarlos o puedes representarlos como JSON y luego pasarlos entre los diferentes entornos. Sin embargo, si mutas uno en un lugar, no lo estás mutando en el otro. Ninguno de los web workers que vamos a ver hoy tiene acceso al DOM. Por ejemplo, el objeto document global no está disponible dentro de los web workers. Si utilizas el shared array buffer, si pasas uno de esos entre estos diferentes entornos, se compartirá un puntero a los mismos datos binarios en memoria y así es como podemos tener datos de memoria compartida.

2. Dedicated Workers

Short description:

Un dedicated worker es el tipo más simple de web worker. Tiene un padre y puede cargar otros dedicated workers. Cada worker proporciona un nuevo entorno de JavaScript y puede ejecutarse en un hilo separado. Para trabajar con un dedicated worker, instanciamos una instancia de worker, adjuntamos un controlador de mensajes y enviamos mensajes utilizando postMessage. El archivo worker.js maneja los mensajes recibidos del padre y puede realizar cálculos intensivos en CPU antes de enviar un mensaje de vuelta.

acceso. Y gran parte de esta explicación es una simplificación de algunas complejidades internas en relación con el contexto y los reinos y cómo funciona realmente la VM de JavaScript. Muy bien. Ahora, veamos los dedicated workers. ¿Qué es un dedicated worker? Bueno, un dedicated worker es el tipo más simple de los web workers que vamos a ver. Cada uno de estos dedicated workers puede tener exactamente un padre. De hecho, puedes cargarlos jerárquicamente si quieres donde los dedicated workers también pueden cargar otros dedicated workers. Y cada uno de estos workers nos proporciona un nuevo entorno de JavaScript. Cada uno también puede ejecutarse en un hilo separado.

Ahora, veamos un ejemplo de código. Así es como trabajaríamos con un dedicated worker desde el contexto de la página web. Tal vez esto se encuentre en un archivo index.html. Tal vez se encuentre dentro de main.js cargado por un archivo HTML. Pero en cualquier caso, esto se ejecuta en el hilo principal que dibuja la ventana. Y así, los navegadores modernos nos proporcionan un objeto global con mayúscula W, worker. Podemos instanciar eso para crear una instancia de un worker. El argumento de esto es la ruta a un archivo que queremos utilizar como el worker. Una vez que obtenemos el worker, podemos adjuntar un controlador de mensajes en él. Aquí estoy asignando this.onmessage, que es una función de devolución de llamada. Cuando se llama a esta función, imprimirá el mensaje del worker y luego imprimirá los datos que se le pasaron. Este código se ejecutará dentro del hilo padre cuando el hilo del dedicated worker le haya pasado un mensaje. Y a la inversa, si queremos pasar un mensaje al worker, llamamos a worker.postMessage donde pasamos un argumento. Estoy pasando una cadena, pero también podríamos pasar otros valores simples o objetos básicos con algunas advertencias. Y finalmente, al final del archivo, simplemente estamos registrando que se ha ejecutado el final del archivo main.js. Ahora veamos el dedicated worker dentro del worker. Este es nuestro archivo worker.js que se mencionó en la diapositiva anterior. En este archivo, lo primero que hacemos es registrar que estamos dentro del worker. Luego asignamos un controlador global onmessage, que acepta el mensaje que se le pasó desde el padre. Y dentro de este controlador, registramos un mensaje que hemos recibido un mensaje de main, registramos los datos que se nos pasaron. En este punto de la aplicación, este podría ser un buen lugar para realizar un cálculo intensivo en CPU. Y finalmente, podemos llamar a postMessageGlobal para enviar un mensaje de vuelta al padre.

3. Ejecución de código y Workers dedicados/compartidos

Short description:

Vamos a ejecutar el código y ver la salida. Vemos el mensaje 'Hola desde Main', que se pasa al hijo. El mensaje luego es recibido y procesado por el worker. El worker imprime 'hola desde el worker' y 'mensaje de Main al worker'. También se imprime el mensaje final del worker. Los workers dedicados proporcionan acceso a un hilo adicional, lo que permite descargar trabajos intensivos en CPU y evitar ralentizaciones. Sin embargo, si el padre muere, el worker dedicado también morirá. Los workers compartidos pueden tener múltiples padres y son útiles para comunicarse entre diferentes ventanas, siempre y cuando sigan las mismas reglas de origen.

Entonces, vamos a ejecutar el código y ver la salida. Aquí ya lo he ejecutado por nosotros. Lo primero que vemos es el mensaje 'Hola desde Main'. Y aunque pasamos el mensaje al hijo, terminamos registrando el mensaje 'Hola desde el final de Main'. Pasa un tiempo no determinista antes de que el mensaje sea recibido y procesado por el worker. Dentro de él, imprimimos 'hola desde el worker' y luego imprimimos 'mensaje de Main al worker'. Finalmente, se imprime el mensaje que se devolvió al hilo padre. Desde el worker, mensaje del worker, ese es el mensaje final allí. Entonces, ¿por qué querrías usar un worker dedicado? Bueno, la razón más importante en mi opinión es que proporciona acceso a un hilo adicional. Es una excelente manera de descargar trabajos intensivos en CPU o cosas que podrían ralentizar un navegador web. Cosas que podrían causar tartamudeo al desplazarse, puedes descargarlas en este hilo adicional. Y así, pasas el mensaje al hilo y luego el hilo principal puede realizar otro trabajo. Y una vez que recibe un mensaje de vuelta de ese worker dedicado, puede manejar ese valor y luego continuar con lo que está haciendo. Una cosa a tener en cuenta es que un worker dedicado, cada vez que su único padre muere, ese worker dedicado también morirá.

A continuación, vamos a ver los workers compartidos. ¿Qué es un worker compartido? Bueno, un worker compartido es bastante similar, pero puede tener múltiples padres. Es útil para comunicarse entre diferentes ventanas. Hay una advertencia de que estas ventanas deben estar en el mismo origen. Por ejemplo, no puedes tener la página web de Google comunicándose con la página web de Microsoft. Deben seguir las mismas reglas de origen. Entonces, nuevamente, veamos un código de ejemplo. Primero, vamos a ver el código que podría ejecutarse en una página HTML. Y así, podemos fingir que tenemos dos páginas HTML diferentes. Ambas tienen un script. Una es la página HTML roja y la otra es la página HTML azul. Dentro de estos archivos, tenemos una etiqueta de script que instancia un worker compartido. El worker compartido está disponible nuevamente en navegadores modernos con una pequeña advertencia que cubriré al final. Al igual que con los otros workers, instanciamos el worker compartido y pasamos un argumento, que es la ruta al archivo que se utilizará como el archivo del worker. Sin embargo, la API para interactuar con él es ligeramente diferente, donde en lugar de asignar directamente una propiedad onMessage al worker, la asignamos a un puerto. Y así, esa propiedad del puerto

4. Using Shared Workers

Short description:

La interfaz del worker compartido es similar al worker dedicado, con una devolución de llamada que toma un argumento de evento. Pasamos un mensaje al worker compartido usando worker.port.postMessage. En el archivo JavaScript del worker compartido, generamos un ID, imprimimos un mensaje de registro, creamos un conjunto llamado ports para almacenar los puertos pasados y manejamos las conexiones usando el método onconnect. Extraemos el puerto de la conexión, lo agregamos al conjunto de puertos y registramos la conexión y el número de páginas conectadas. También asignamos un controlador onmessage al puerto para manejar los mensajes entrantes. Con los workers compartidos, podemos tener múltiples padres, por lo que iteramos sobre el conjunto de puertos y llamamos a postMessage en cada puerto para enviar un mensaje de vuelta. Ejecutemos este código en nuestra máquina.

representa un puerto de comunicación dentro del propio worker. Y así, la interfaz, por lo demás, esto es bastante similar al worker dedicado, donde es una devolución de llamada que toma un argumento de evento con una propiedad data que se pasa a ella. En este caso, solo estamos registrando un mensaje que dice que hemos recibido un evento. Y luego, más adelante, lo que queremos hacer es pasar un mensaje al worker compartido desde uno de los archivos HTML. Y para hacer eso, llamaríamos a worker.port.postMessage, pasando el mensaje que queremos enviar.

Bien. Aquí hay un código sobre cómo usar el worker compartido desde la perspectiva del worker. Este es nuestro archivo JavaScript del worker compartido. Ahora, hay un poco de complejidad aquí y trataré de explicarlo paso a paso. Pero realmente, el propósito de esto es simplemente mostrar cómo funciona el worker compartido. Lo primero que hago en el worker compartido es generar un ID. Ese número es solo un número aleatorio grande para mostrar que este código solo se ejecutará una vez. Y luego, lo siguiente que hacemos es imprimir un mensaje de registro que dice que estamos dentro del archivo shared.js y registramos ese ID nuevamente. A continuación, creamos una variable llamada ports. Y eso es un conjunto que contendrá los puertos que se le pasen a él. Después de eso, tenemos un método onconnect que se asigna a self. Y así, esto es una devolución de llamada que se llama cada vez que una página web diferente establece una conexión con el worker compartido. Entonces, si alguna vez has trabajado con websockets, este patrón de código podría resultarte un poco familiar. Lo primero que hacemos es extraer el puerto de la conexión y luego lo agregamos a nuestro conjunto de puertos. Y luego simplemente registramos que se ha establecido una conexión. Registramos el ID nuevamente y también el tamaño de los puertos, que nos dirá cuántas páginas están conectadas. Después de eso, asignamos un controlador onmessage al propio puerto, y eso indica que cuando este puerto reciba un mensaje. Entonces, cuando una de las páginas HTML envíe un mensaje a este worker compartido, queremos poder manejarlo aquí. Nuevamente, registraremos el mensaje, diremos que se recibió el mensaje, se pasó el ID en los datos. Ahora, anteriormente con el worker dedicado, cuando queríamos enviar un mensaje de vuelta al padre, era bastante sencillo. Había un solo puerto y simplemente enviábamos el mensaje a través de él. Sin embargo, con los workers compartidos, dado que podemos tener más de un padre, es por eso que estamos agregando cada uno de los puertos al conjunto de puertos, y luego los estamos iterando aquí y llamando al método postMessage en cada uno de ellos. Ahora, postMessage solo nos permite enviar un solo valor a través de él. Sin embargo, en este caso, estoy abusando un poco de un array para pasar el ID y los datos que se recibieron también. Y así que digamos que realmente ejecutamos este código en nuestra

5. Shared Worker Communication and Usage

Short description:

Abrimos el archivo red.html y se ejecuta el archivo shared.js. Se genera un ID, se establece una conexión y el archivo red.html se conecta al worker compartido. Abrimos el archivo blue.html, se emite otra conexión y ahora el número de conexiones es dos. Pasamos un mensaje al worker compartido y este imprime el mensaje recibido y su ID. Los mensajes se envían a los archivos HTML que los llaman. No hay garantía sobre el orden de ejecución. Los workers compartidos son útiles para la comunicación entre páginas y para mantener ámbitos de variables. No son compatibles con Safari, pero funcionan en Chrome y Firefox. Si se necesita coordinación entre páginas, se puede utilizar el canal de difusión como alternativa. Un worker compartido se cierra cuando su último padre se cierra.

máquina. Así que tal vez lo primero que hagamos sea abrir el archivo red.html. Y entonces, lo que sucede, vamos a ver que se ejecuta el archivo shared.js. Y vemos que se generó un ID. Ese ID es 1, 2, 3, 4, 5, 6. Y luego vemos que se establece una conexión. Y el archivo red.html se conecta al worker compartido. Y nuevamente, imprimimos ese ID. Y el ID es el mismo.

Luego abrimos el otro archivo. Abrimos el archivo blue.html. En ese momento, vemos que se emite otra conexión. Y el ID se repite nuevamente. Y vemos que el número de conexiones ahora es dos. Y después de eso, ejecutamos el ejemplo de postMessage de dos diapositivas anteriores, donde pasamos el mensaje, hola, mundo, al worker compartido. Y cuando eso sucede, el worker compartido imprime que recibió un mensaje, imprime su ID nuevamente y el mensaje que recibió. Y luego envía esos mensajes a los archivos HTML que los llaman. Y cuando eso sucede, se llama a la línea de evento, se imprimen las dos últimas líneas de evento en la pantalla. Y esas se verán dentro de la consola del inspector en esas páginas específicas.

No hay una garantía en este caso sobre el orden en que se realizan los registros del archivo blue HTML. Esa es un poco la emoción divertida de la multihilo, que no siempre hay una garantía sobre el orden en que se ejecuta esto. Entonces, ¿por qué podrías usar un worker compartido? Bueno, tal vez necesites comunicarte entre páginas. Es bastante útil para mantener, como, un contexto con variables asociadas, y especialmente en casos en los que deseas que esos ámbitos de variables sobrevivan más allá de la vida de una página. Y así, tal vez algunas aplicaciones de una sola página más pesadas dependan de esto. Realmente queremos coordinar cosas entre diferentes páginas. Entonces, otro patrón es tal vez quieres crear un singleton, ya sabes, una única fuente de verdad, y quieres que se acceda a ella desde diferentes páginas. Una cosa a tener en cuenta es que, desafortunadamente, los workers compartidos no son compatibles con Safari. Creo que los admitieron en algún momento, pero luego, por consideraciones de security, terminaron eliminándolos. Sin embargo, funcionan en Chrome y Firefox. Si te encuentras necesitando un patrón para coordinar la comunicación entre diferentes páginas, puedes considerar utilizar el canal de difusión como alternativa, y eso también está disponible en navegadores modernos. Ahora, una cosa a tener en cuenta es que un worker compartido se cerrará cuando su último padre se cierre, por lo que si abrimos varias páginas, tal vez terminemos abriendo 10 de ellas, no será hasta que, luego, comiences a cerrar estas diferentes páginas y no será hasta que cierres la página final que el worker compartido terminará siendo eliminado también.

6. Service Workers and Intercepting Requests

Short description:

Los service workers son los más complejos de los web workers. Pueden interceptar y hacer de proxy en las solicitudes realizadas desde una página web, incluyendo solicitudes fetch, solicitudes AJAX y activos cargados. Los service workers pueden técnicamente no tener padres y ejecutarse en segundo plano. Se pueden utilizar para compartir estado entre ventanas del mismo origen. Para crear un service worker, utilizamos el método navigator.serviceWorker.register con una ruta al archivo del worker y un objeto de configuración. La propiedad scope define el rango de URL que el worker puede controlar. Podemos manejar cambios de estado, como oncontrollerchange, y registrar mensajes cuando el service worker toma el control de la página. La función makeRequest obtiene datos de un archivo y los registra en la pantalla. El archivo del service worker, sw.js, es donde se implementa la lógica del service worker.

También puedes terminar manualmente estos web workers si así lo deseas. Muy bien, finalmente, echemos un vistazo a los service workers. ¿Qué es un service worker? Bueno, un service worker es el más complejo de los web workers. La característica más genial que admiten es la capacidad de interceptar o hacer de proxy en las solicitudes que se realizan a un servidor desde una página web. Esto incluye cosas como solicitudes fetch, solicitudes AJAX, pero también incluye cosas como imágenes que se cargan, activos que se cargan desde CSS, el archivo favicon. Muchas de esas cosas, básicamente todas, terminan pasando a través del service worker.

Algo interesante sobre el service worker es que técnicamente puede no tener padres y se ejecuta en segundo plano. Por lo tanto, necesitas una página para ejecutarse y terminar instalando el service worker. Pero una vez que esa página se cierra, el service worker técnicamente permanece instalado en el navegador. El comportamiento de cuándo aparece y desaparece, cuándo vive y muere, es un poco menos definido en el sentido de que no es algo en lo que necesariamente quieras depender. Por lo tanto, puedes usar los service workers para compartir estado entre ventanas del mismo origen también. Muy bien. Veamos otro ejemplo de código. En este caso, cuando vemos los service workers en la página web, nuevamente, en este caso, la interfaz para crear el worker es un poco diferente. Aquí estamos llamando a navigator.service Worker.register. Al igual que con los otros web workers, el primer argumento es una ruta al archivo que representa al worker. También hay un objeto de configuración adicional, y la propiedad de configuración más comúnmente utilizada es el ámbito (scope). Por lo tanto, el ámbito nos permite definir el rango de URL que el worker puede controlar. En este caso, estamos diciendo que todo lo que se carga y comienza con una barra diagonal está bajo control. Básicamente, estamos diciendo que todo en este dominio está bajo control. También obtenemos algunos cambios de estado diferentes a los que podemos acceder. En este caso, estamos manejando el evento oncontrollerchange, y simplemente vamos a registrar un mensaje en la pantalla. Por lo tanto, lo que dice es que, cuando la página actual, cuando un service worker toma el control de la página, lo que significa que en ese momento las solicitudes son interceptadas, vamos a registrar un mensaje que indique que ahora está funcionando. Entonces, la última función que tenemos aquí es makeRequest. Esto es solo con fines ilustrativos, y lo ejecutaremos en un momento. Pero lo que hace es hacer una solicitud fetch a un archivo en el servidor actual llamado data.json. Deserializa el resultado y luego lo registra en la pantalla. Muy bien, ahora veamos los service workers dentro del propio worker. Este es nuestro archivo sw.js. Esta es la primera mitad.

7. Service Worker Installation and Activation

Short description:

Creamos una variable llamada contador y la establecemos en cero. El método on install registra un mensaje cuando el service worker se instala. El método on activate registra un mensaje cuando el service worker se activa. El service worker intercepta las solicitudes de las páginas abiertas actualmente después de que se actualizan. El controlador on fetch registra la URL recibida y verifica si termina en data.json. Si no es así, se realiza una solicitud HTTP normal. Si lo hace, se incrementa la variable contador y se crea una nueva respuesta con un objeto JSON que contiene el contador. El tipo de contenido se establece en text.JSON. Los registros muestran la instalación, activación y cambio de controlador del service worker, pero su orden no está garantizado.

Entonces, lo primero que estamos haciendo aquí es crear una variable llamada contador y la establecemos en cero. A continuación, asignamos un método on install en nuestro objeto self y eso nos dice cuándo se está instalando el service worker. En este caso, simplemente vamos a registrar un mensaje de que se ha realizado la instalación.

Después de eso, tenemos un on activate, y esto se llama cuando el service worker alcanza la etapa o estado de activación, ya que estos service workers actúan como una máquina de estados. Entonces, cuando esto sucede, simplemente vamos a registrar un mensaje de que el service worker está ahora activo, pero también vamos a hacer algo más interesante. Cuando un service worker se activa por primera vez, las páginas abiertas, las solicitudes que envían no se envían inmediatamente a través de este service worker. No es hasta que la página se actualiza que esas páginas quedan bajo el control del service worker. Entonces, lo que estamos haciendo aquí en la parte inferior, estamos llamando a event.waitUntil, que acepta una promesa, y la promesa es el resultado de la llamada self.clients.claim. Eso significa básicamente que las páginas que están abiertas actualmente, el service worker interceptará la solicitud. Muy bien. El archivo continúa y aquí está la segunda mitad. También tenemos este controlador on fetch. Este controlador on fetch se llama cada vez que el service worker recibe una solicitud de red de una de las páginas web. Entonces, dentro de este controlador, lo que estamos haciendo primero es registrar la URL que se recibió. A continuación, tenemos una declaración if, por lo que aquí verificamos si la URL que se recibió termina en data.json. Si no es así, entonces saltamos al final y volvemos esencialmente a una solicitud HTTP normal. Entonces, aquí tenemos este evento que responde con, y eso acepta una promesa que se resuelve en un valor que se le da al navegador como resultado de la solicitud. Y así, el valor que le estamos dando es la respuesta de fetch, que es una promesa, y luego el argumento que proporcionamos a fetch es la solicitud entrante, que es event.request. Entonces, básicamente, lo que esa línea está diciendo es simplemente realizar una solicitud normal y no hacer nada con ella. Sin embargo, si la URL terminó en data.JSON, ejecutamos el cuerpo de esa declaración if. Entonces, lo que hacemos allí es incrementar esa variable contador de antes, y luego simplemente llamamos a event.respondWith, puedes ignorar ese return void, pero simplemente llamamos a event.respondWith, donde pasamos una nueva respuesta que estamos creando desde cero. Y así, el cuerpo de esa respuesta es un objeto JSON que contiene nuestro contador en la variable. Y luego, solo con fines ilustrativos, establecemos las cabeceras, por lo que en este caso, establecemos el tipo de contenido en text.JSON. Y así, si ejecutamos este código, estos son los registros que veremos. Entonces, lo primero que vemos es que se ha instalado el service worker. A continuación, vemos que el service worker ha sido activado. Y luego, finalmente, vemos que ha ocurrido un cambio de controlador. Nuevamente, el orden de estos mensajes no es determinista, ya que el navegador, ya sabes, puede manejar un registro y almacenarlo en memoria. Bueno, imprimirá un registro desde otra ubicación.

8. Using Service Workers and Web Worker Comparison

Short description:

A continuación, llamamos a make request desde la página web, lo que hará nuestra solicitud fetch al servidor. main.js recibe ese mensaje e imprime el resultado, que en este caso es el contador establecido en 1. Los service workers son útiles para almacenar en caché activos de red, realizar sincronización en segundo plano, admitir notificaciones push y crear aplicaciones web progresivas. Sin embargo, la vida útil de un service worker no está garantizada y se recomienda utilizar las API de caché para el almacenamiento persistente. Los workers dedicados, compartidos y de servicio proporcionan hilos adicionales para fines de multiprocesamiento y tienen características y casos de uso diferentes.

Entonces, el orden de estos primeros dos mensajes no está garantizado. A continuación, llamamos a make request desde la página web, lo que hará nuestra solicitud fetch al servidor. Entonces, eso sucede. Imprimimos que se realizó la solicitud fetch. Simplemente imprime la URL que se recibió y luego devuelve el objeto JavaScript a través de la solicitud de red. Y finalmente, main.js recibe ese mensaje e imprime el resultado, que en este caso es el contador establecido en 1. Y luego, si ejecutamos la función make request varias veces, cada una de esas solicitudes dará como resultado un contador diferente.

Entonces, ninguna de estas solicitudes se envía realmente a ese servidor que se ejecuta en localhost puerto 500, todas son manejadas por el service worker. Entonces, ¿por qué querrías usar un service worker? Bueno, es realmente útil para almacenar en caché activos de red si una aplicación está sin conexión. Puedes usarlo para realizar sincronización en segundo plano de contenido que se actualiza, y si actualizas contenido en el servidor, el service worker puede decidir cómo devolverlo al cliente. Si deseas admitir notificaciones push, eso también se hace en el service worker. Si eres como yo y te gusta crear aplicaciones web progresivas y quieres que esas aplicaciones se agreguen a la pantalla de inicio, tanto Android con Chrome como iOS con Safari utilizarán estos service workers, y es uno de los requisitos antes de poder agregar tu PWA a la pantalla de inicio. Una cosa a tener en cuenta es que un service worker puede morir cuando muere el último padre, pero sigue existiendo y no hay una garantía de cuánto tiempo permanecerán esos cierres en memoria. Entonces, si piensas en el ejemplo que mencioné con esa variable contador, en realidad es un poco un patrón incorrecto. Realmente no querrías crear un estado en memoria en un service worker donde esperarías que permanezca. Y si deseas hacer cosas que sean un poco más persistentes, por ejemplo, si deseas poner cosas en cachés. Hay todo tipo de API de caché disponibles dentro de los service workers para mantener esos datos en un estado más persistente. Entonces, si quisieras tomar una captura de pantalla de esta presentación, esta es probablemente la que debes hacer. Y así, aquí tenemos una comparación entre los diferentes tipos de workers web. Y así, a la izquierda, tengo la característica y luego cómo funciona para los workers dedicados, compartidos y de servicio. Y así, los tres de estos workers web, cada uno de ellos proporcionará un hilo adicional que se puede utilizar para fines de multiprocesamiento. Si tienes un servidor que no sirve contenido a través de HTTPS, pero solo puedes usar workers dedicados y compartidos, no puedes usar un service worker con él. Si necesitas soporte para Safari, puedes usar workers dedicados y de servicio, pero debes evitar un worker compartido. Si deseas actuar como un proxy HTTP, entonces debes usar un service worker. Un worker dedicado tiene un padre, un worker compartido tiene al menos un padre, y un service worker tiene al menos cero padres. Y luego, un worker dedicado muere con su padre, un worker compartido muere con su último padre y un service worker es un poco más complicado. Muy bien. Esa ha sido la presentación. Esta fue una comparación de los workers web. Si quieres seguirme, estoy en Twitter en tlhunter. Esta presentación está disponible en ese enlace bit.ly en línea. Y si estás interesado en obtener más información sobre el libro, no dudes en seguir ese último enlace también. ¡Gracias!

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
Do you have a large product built by many teams? Are you struggling to release often? Did your frontend turn into a massive unmaintainable monolith? If, like me, you’ve answered yes to any of those questions, this talk is for you! I’ll show you exactly how you can build a micro frontend architecture with Remix to solve those challenges.
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Top Content
Remix is a web framework that gives you the simple mental model of a Multi-Page App (MPA) but the power and capabilities of a Single-Page App (SPA). One of the big challenges of SPAs is network management resulting in a great deal of indirection and buggy code. This is especially noticeable in application state which Remix completely eliminates, but it's also an issue in individual components that communicate with a single-purpose backend endpoint (like a combobox search for example).
In this talk, Kent will demonstrate how Remix enables you to build complex UI components that are connected to a backend in the simplest and most powerful way you've ever seen. Leaving you time to chill with your family or whatever else you do for fun.
JSNation Live 2021JSNation Live 2021
29 min
Making JavaScript on WebAssembly Fast
Top Content
JavaScript in the browser runs many times faster than it did two decades ago. And that happened because the browser vendors spent that time working on intensive performance optimizations in their JavaScript engines.Because of this optimization work, JavaScript is now running in many places besides the browser. But there are still some environments where the JS engines can’t apply those optimizations in the right way to make things fast.We’re working to solve this, beginning a whole new wave of JavaScript optimization work. We’re improving JavaScript performance for entirely different environments, where different rules apply. And this is possible because of WebAssembly. In this talk, I'll explain how this all works and what's coming next.
React Summit 2023React Summit 2023
24 min
Debugging JS
As developers, we spend much of our time debugging apps - often code we didn't even write. Sadly, few developers have ever been taught how to approach debugging - it's something most of us learn through painful experience.  The good news is you _can_ learn how to debug effectively, and there's several key techniques and tools you can use for debugging JS and React apps.
Node Congress 2022Node Congress 2022
26 min
It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Top Content
Do you know what’s really going on in your node_modules folder? Software supply chain attacks have exploded over the past 12 months and they’re only accelerating in 2022 and beyond. We’ll dive into examples of recent supply chain attacks and what concrete steps you can take to protect your team from this emerging threat.
You can check the slides for Feross' talk here.

Workshops on related topic

React Day Berlin 2022React Day Berlin 2022
86 min
Using CodeMirror to Build a JavaScript Editor with Linting and AutoComplete
Top Content
WorkshopFree
Using a library might seem easy at first glance, but how do you choose the right library? How do you upgrade an existing one? And how do you wade through the documentation to find what you want?
In this workshop, we’ll discuss all these finer points while going through a general example of building a code editor using CodeMirror in React. All while sharing some of the nuances our team learned about using this library and some problems we encountered.
Node Congress 2023Node Congress 2023
109 min
Node.js Masterclass
Workshop
Have you ever struggled with designing and structuring your Node.js applications? Building applications that are well organised, testable and extendable is not always easy. It can often turn out to be a lot more complicated than you expect it to be. In this live event Matteo will show you how he builds Node.js applications from scratch. You’ll learn how he approaches application design, and the philosophies that he applies to create modular, maintainable and effective applications.

Level: intermediate
TestJS Summit - January, 2021TestJS Summit - January, 2021
173 min
Testing Web Applications Using Cypress
WorkshopFree
This workshop will teach you the basics of writing useful end-to-end tests using Cypress Test Runner.
We will cover writing tests, covering every application feature, structuring tests, intercepting network requests, and setting up the backend data.
Anyone who knows JavaScript programming language and has NPM installed would be able to follow along.
Node Congress 2023Node Congress 2023
63 min
0 to Auth in an Hour Using NodeJS SDK
WorkshopFree
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool.
We will enhance a full-stack JS application (Node.JS backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:- User authentication - Managing user interactions, returning session / refresh JWTs- Session management and validation - Storing the session for subsequent client requests, validating / refreshing sessions
At the end of the workshop, we will also touch on another approach to code authentication using frontend Descope Flows (drag-and-drop workflows), while keeping only session validation in the backend. With this, we will also show how easy it is to enable biometrics and other passwordless authentication methods.
Table of contents- A quick intro to core authentication concepts- Coding- Why passwordless matters
Prerequisites- IDE for your choice- Node 18 or higher
JSNation 2023JSNation 2023
104 min
Build and Deploy a Backend With Fastify & Platformatic
WorkshopFree
Platformatic allows you to rapidly develop GraphQL and REST APIs with minimal effort. The best part is that it also allows you to unleash the full potential of Node.js and Fastify whenever you need to. You can fully customise a Platformatic application by writing your own additional features and plugins. In the workshop, we’ll cover both our Open Source modules and our Cloud offering:- Platformatic OSS (open-source software) — Tools and libraries for rapidly building robust applications with Node.js (https://oss.platformatic.dev/).- Platformatic Cloud (currently in beta) — Our hosting platform that includes features such as preview apps, built-in metrics and integration with your Git flow (https://platformatic.dev/). 
In this workshop you'll learn how to develop APIs with Fastify and deploy them to the Platformatic Cloud.
JSNation Live 2021JSNation Live 2021
156 min
Building a Hyper Fast Web Server with Deno
WorkshopFree
Deno 1.9 introduced a new web server API that takes advantage of Hyper, a fast and correct HTTP implementation for Rust. Using this API instead of the std/http implementation increases performance and provides support for HTTP2. In this workshop, learn how to create a web server utilizing Hyper under the hood and boost the performance for your web apps.