Una panoramica dei web worker

Gran parte dei contenuti di questo corso finora è stata incentrata su concetti quali considerazioni generali sulle prestazioni HTML, suggerimenti sulle risorse, ottimizzazione di vari tipi di risorse per migliorare il tempo di caricamento iniziale della pagina e la reattività all'input dell'utente, nonché il caricamento lento di risorse specifiche.

Tuttavia, c'è un aspetto delle prestazioni relativo a JavaScript che non è ancora stato trattato in questo corso, e questo è il ruolo dei web worker nel migliorare la reattività all'input, di cui si parla in questo modulo e nel modulo successivo.

JavaScript viene spesso descritto come un linguaggio a thread unico. In pratica, questo fa riferimento al thread principale, ovvero l'unico thread in cui il browser esegue la maggior parte del lavoro che vedi nel browser. Questo lavoro include attività relative a elementi come lo scripting, alcuni tipi di operazioni di rendering, l'analisi HTML e CSS e altri tipi di lavori rivolti agli utenti che migliorano l'esperienza utente. In realtà, i browser utilizzano altri thread per svolgere operazioni a cui in genere tu, in qualità di sviluppatore, non disponi dell'accesso diretto, ad esempio i thread GPU.

Per quanto riguarda JavaScript, in genere si lavora sul thread principale, ma solo per impostazione predefinita. È possibile registrare e utilizzare thread aggiuntivi in JavaScript. La funzionalità che consente il multi-threading in JavaScript è nota come API Web Workers.

I web worker sono utili quando hai un lavoro dispendioso in termini di calcolo che non può essere eseguito sul thread principale senza causare attività lunghe che impediscono la risposta della pagina. Queste attività possono certamente influire sull'Interaction to Next Paint (INP) del tuo sito web, perciò può essere utile sapere quando hai un lavoro da eseguire completamente al di fuori del thread principale. Così facendo puoi creare più spazio per altre attività nel thread principale, in modo da velocizzare le interazioni degli utenti.

Questo modulo e la demo successiva che mostra un caso d'uso concreto riguardano i web worker. La demo mostra come utilizzare un web worker per leggere i metadati dell'immagine da un file JPEG al di fuori del thread principale e come far sì che tali metadati vengano riportati nel thread principale affinché l'utente possa vederli.

Come viene lanciato un web worker

Un web worker viene registrato creando un'istanza del classe Worker. In questo caso devi specificare la posizione del codice del web worker, che viene caricato dal browser e per il quale viene creato successivamente un nuovo thread. Il thread risultante è spesso chiamato thread di lavoro.

const myWebWorker = new Worker('/js/my-web-worker.js');

Nel file JavaScript del worker, in questo caso my-web-worker.js, puoi scrivere codice che viene quindi eseguito in un thread worker separato.

Limitazioni dei web worker

A differenza di JavaScript che viene eseguito nel thread principale, i web worker non hanno accesso diretto al contesto window e hanno accesso limitato alle API che forniscono. I web worker sono soggetti ai seguenti vincoli:

  • I web worker non possono accedere direttamente al DOM.
  • I web worker possono comunicare con il contesto window attraverso una pipeline di messaggistica, il che significa che un web worker può accedere indirettamente al DOM in un determinato modo.
  • L'ambito del web worker è self, anziché window.
  • L'ambito web worker ha accesso a primitive e costruzioni JavaScript, nonché ad API come fetch e a un numero abbastanza elevato di altre API.

In che modo i web worker comunicano con window

Un web worker può comunicare con il contesto window del thread principale attraverso una pipeline di messaggistica. Questa pipeline consente di trasferire i dati da e verso il thread principale e il web worker. Per inviare dati da un web worker al thread principale, devi configurare un evento message nel contesto del web worker (self)

// my-web-worker.js
self.addEventListener("message", () => {
  // Sends a message of "Hellow, window!" from the web worker:
  self.postMessage("Hello, window!");
});

Quindi, in uno script nel contesto window nel thread principale, puoi ricevere il messaggio dal thread di worker web utilizzando un altro evento message:

// scripts.js

// Creates the web worker:
const myWebWorker = new Worker('/js/my-web-worker.js');

// Adds an event listener on the web worker instance that listens for messages:
myWebWorker.addEventListener("message", ({ data }) => {
  // Echoes "Hello, window!" to the console from the worker.
  console.log(data);
});

La pipeline di messaggistica del web worker è una sorta di escape hatch dal contesto del web worker. Utilizzandolo, puoi inviare dati a window dal web worker per aggiornare il DOM oppure eseguire altre operazioni da eseguire sul thread principale.

verifica le tue conoscenze

Su quale thread viene eseguito un web worker?

Il thread principale.
Riprova.
Un proprio thread (noto anche come thread di lavoro web).
risposta esatta.
Il thread della GPU.
Riprova.

A cosa può accedere un web worker?

Primitive JavaScript, come array e oggetti.
risposta esatta.
Un sottoinsieme rigoroso di API disponibili nel contesto window, tra cui fetch.
risposta esatta.
Il contesto window, ma solo indirettamente.
risposta esatta.

In che modo un web worker può accedere al contesto "finestra"?

Direttamente, facendo riferimento ai membri dell'oggetto window.
Riprova.
Un web worker non può accedere a window in alcun modo.
Riprova.
Tramite una pipeline di messaggistica facilitata dal metodo postMessage nel contesto del web worker (self).
risposta esatta.

A seguire: un caso d'uso concreto dei web worker

Nel prossimo modulo viene descritto e mostrato in dettaglio un caso d'uso concreto dei web worker. In questo modulo, un web worker viene utilizzato per recuperare un file JPEG da un determinato URL e leggere i relativi metadati Exif in un web worker. Quei dati vengono poi inviati al thread principale per essere mostrati all'utente.