HTML5 - Web Workers

JavaScript è stato progettato per essere eseguito in un ambiente a thread singolo, il che significa che più script non possono essere eseguiti contemporaneamente. Considera una situazione in cui devi gestire eventi dell'interfaccia utente, eseguire query ed elaborare grandi quantità di dati API e manipolare il DOM.

JavaScript bloccherà il browser in situazioni in cui l'utilizzo della CPU è elevato. Facciamo un semplice esempio in cui JavaScript passa attraverso un grande ciclo:

<!DOCTYPE HTML>

<html>
   <head>
      <title>Big for loop</title>
      
      <script>
         function bigLoop() {
            
            for (var i = 0; i <= 10000; i += 1) {
               var j = i;
            }
            alert("Completed " + j + "iterations" );
         }
         
         function sayHello(){
            alert("Hello sir...." );
         }
      </script>
      
   </head>
   
   <body>
      <input type = "button" onclick = "bigLoop();" value = "Big Loop" />
      <input type = "button" onclick = "sayHello();" value = "Say Hello" />
   </body>
</html>

Produrrà il seguente risultato:

Quando fai clic sul pulsante Big Loop, viene visualizzato il seguente risultato in Firefox:

Che cosa sono i web worker?

La situazione spiegata sopra può essere gestita utilizzando Web Workers che eseguirà tutte le attività computazionalmente costose senza interrompere l'interfaccia utente e in genere verrà eseguito su thread separati.

I Web Worker consentono script di lunga durata che non vengono interrotti da script che rispondono ai clic o ad altre interazioni dell'utente e consentono l'esecuzione di attività lunghe senza cedere per mantenere la pagina reattiva.

I web worker sono script in background e sono relativamente pesanti e non sono destinati ad essere utilizzati in gran numero. Ad esempio, sarebbe inappropriato avviare un worker per ogni pixel di un'immagine da quattro megapixel.

Quando uno script è in esecuzione all'interno di un Web Worker, non può accedere all'oggetto finestra della pagina Web (window.document), il che significa che i Web Worker non hanno accesso diretto alla pagina Web e all'API DOM. Sebbene i web worker non possano bloccare l'interfaccia utente del browser, possono comunque consumare cicli della CPU e rendere il sistema meno reattivo.

Come lavorano i web worker?

I web worker vengono inizializzati con l'URL di un file JavaScript, che contiene il codice che il worker eseguirà. Questo codice imposta i listener di eventi e comunica con lo script che lo ha generato dalla pagina principale. La seguente è la semplice sintassi:

var worker = new Worker('bigLoop.js');

Se il file javascript specificato esiste, il browser genererà un nuovo thread di lavoro, che viene scaricato in modo asincrono. Se il percorso del tuo lavoratore restituisce un errore 404, il lavoratore fallirà silenziosamente.

Se la tua applicazione ha più file JavaScript di supporto, puoi importarli importScripts() metodo che accetta i nomi dei file come argomenti separati da virgola come segue:

importScripts("helper.js", "anotherHelper.js");

Una volta che il web worker è stato generato, la comunicazione tra il web worker e la sua pagina principale viene eseguita utilizzando il file postMessage()metodo. A seconda del browser / versione, postMessage () può accettare una stringa o un oggetto JSON come singolo argomento.

Si accede al messaggio passato da Web Worker utilizzando onmessageevento nella pagina principale. Ora scriviamo il nostro esempio bigLoop utilizzando Web Worker. Di seguito è la pagina principale (ciao.htm) che genererà un web worker per eseguire il ciclo e per restituire il valore finale della variabilej -

<!DOCTYPE HTML>

<html>
   <head>
      <title>Big for loop</title>
      
      <script>
         var worker = new Worker('bigLoop.js');
         
         worker.onmessage = function (event) {
            alert("Completed " + event.data + "iterations" );
         };
         
         function sayHello() {
            alert("Hello sir...." );
         }
      </script>
   </head>
   
   <body>
      <input type = "button" onclick = "sayHello();" value = "Say Hello"/>
   </body>
</html>

Di seguito è riportato il contenuto del file bigLoop.js. Questo fa uso dipostMessage() API per ritrasmettere la comunicazione alla pagina principale -

for (var i = 0; i <= 1000000000; i += 1) {
   var j = i;
}
postMessage(j);

Questo produrrà il seguente risultato:

Fermare i web worker

I web worker non si fermano da soli ma la pagina che li ha avviati può fermarli chiamando terminate() metodo.

worker.terminate();

Un Web Worker terminato non risponderà più ai messaggi né eseguirà calcoli aggiuntivi. Non puoi riavviare un lavoratore; invece, puoi creare un nuovo lavoratore utilizzando lo stesso URL.

Gestione degli errori

Di seguito viene mostrato un esempio di una funzione di gestione degli errori in un file JavaScript di Web Worker che registra gli errori nella console. Con il codice di gestione degli errori, l'esempio precedente diventerebbe il seguente:

<!DOCTYPE HTML>

<html>
   <head>
      <title>Big for loop</title>
      
      <script>
         var worker = new Worker('bigLoop.js');
         
         worker.onmessage = function (event) {
            alert("Completed " + event.data + "iterations" );
         };
         
         worker.onerror = function (event) {
            console.log(event.message, event);
         };
         
         function sayHello() {
            alert("Hello sir...." );
         }
      </script>
   </head>
   
   <body>
      <input type = "button" onclick = "sayHello();" value = "Say Hello"/>
   </body>
</html>

Verifica del supporto del browser

Di seguito è riportata la sintassi per rilevare il supporto di una funzionalità di Web Worker disponibile in un browser:

<!DOCTYPE HTML>

<html>
   <head>
      <title>Big for loop</title>
      <script src = "/js/modernizr-1.5.min.js"></script>
      
      <script>
      function myFunction() {
         
         if (Modernizr.webworkers) {
            alert("Congratulation!! you have web workers support." );
         } else {
            alert("Sorry!! you do not have web workers support." );
         }
      }
      </script>
   </head>
   
   <body>
      <button onclick = "myFunction()">Click me</button>
   </body>
</html>

Questo produrrà il seguente risultato: