MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

Javascript ha un modello di parallelismo basato su un "event loop". Questo modello è abbastanza differente dai modelli degli altri linguaggi quali, per esempio, C e Java.
 

Runtime

Questa sezione descrive un modello teorico. I moderni engine JavaScript implementano ed ottimizzano pesantemente la semantica descritta.

Rappresentazione grafica

Stack, heap, queue

Stack

Chiamate di funzioni da uno stack di frames.

function f(b){
  var a = 12;
  return a+b+35;
}

function g(x){
  var m = 4;
  return f(m*x);
}

g(21);

Quando viene invocata g, viene creato un primo frame contenente gli argomenti di g e le variabili locali. Quando invoca f, viene creato un secondo frame con un'operazione di push sopra il primo, contenente gli argomenti di f e le variabili locali. Quando esce con il return, viene effettuata un'operazione di pop sullo stack (nel quale rimane quindi solo g). Quando anche g effettua il return, lo stack rimane vuoto.

Heap

L'heap indica una grande regione di memoria perlopiù non strutturata.

Queue

Un runtime JavaScript contiene una coda(queue) di messaggi, ossia una lista di messaggi da essere processati. Ad ogni messaggio è associata una funzione. Quando lo stack è vuoto, viene estratto un messaggio dalla coda e processato, ossia viene chiamata la funzione associata (e, pertanto, viene creato un frame nello stack). L'elaborazione dei messaggi finisce quando lo stack ritorna ad essere vuoto.

Event loop

L'event loop prende il suo nome dalla modalità con cui viene normalmente implementato, ossia tipicamente: 

while(queue.waitForMessage()){
  queue.processNextMessage();
}

queue.waitForMessage attende che arrivi un messaggio quando non c'e' ne sono.

"Run-to-completion"

Ogni messaggio viene completamente elaborato prima di passare ad un altro. Questa dinamica offre alcune comode proprietà quando si ragiona sul proprio programma, incluso il fatto che, fino a che una funzione è in esecuzione, non c'è modo di bloccarla (pre-emption) e completerà la propria esecuzione prima che un altro codice possa essere eseguito (e possa manipolare i dati che la funzione manipola). Questo è completamente diverso dal C, ad esempio, dove, se una funzione è eseguita in un thread, può essere bloccata in qualsiasi momento per eseguire altro codice di un altro thread.   

Un aspetto negativo di questo modello sta nel fatto che se un messaggio impiega troppo tempo ad essere processato, l'applicazione web non puà elaborare le interazioni dell'utente, come i click o gli scroll. Il browser in qualche modo mitiga questa situazione con la finestra "uno script sta impiegando troppo tempo a completare". Una buona pratica da seguire è di implementare l'elaborazione di un messaggio in modo che impieghi poco tempo e, se possibile, suddividere un messaggio in più messaggi.

Aggiungere messaggi

Nei browser web, i messaggi sono continuamente aggiunti ogni qualvolta si verifica un evento con un event listener associato. Quindi il click ad un elemento con un un handler associato aggiungerà un messaggio--così come ogni altro evento.

Una chiamata alla funzione setTimeout aggiunge un messaggio alla coda dopo che il tempo indicato come secondo argomento è trascorso. Se non c'è nessun altro messaggio nella coda, il messaggio è processato immediatamente; al contrario, se ci sono altri messaggi, il messaggio aggiunto da setTimeout dovrà attendere che gli altri messaggi vengano processati. Per questa ragione il secondo argomento di questa funzione indica un tempo minimo e non un tempo garantito.

Intervallo zero

Zero delay non significa in realtà che la funzione di callback verrà attivata dopo zero millisecondi. Una chiamata a setTimeout con un delay di 0 (zero) millisecondi, non esegue la funzione di callback dopo l'intervallo di tempo passato. L'esecuzione dipende dal numero di task in attesa nella coda. Nel seguente esempio il messaggio "this is just a message" verrà stampato a console prima che il messaggio della callback venga processato, perchè il ritardo è il minimo tempo richiesto per elaborare la richiesta, non un tempo garantito.

(function () {

  console.log('this is the start');

  setTimeout(function cb() {
    console.log('this is a msg from call back');
  });

  console.log('this is just a message');

  setTimeout(function cb1() {
    console.log('this is a msg from call back1');
  }, 0);

  console.log('this is the end');

})();

// "this is the start"
// "this is just a message"
// "this is the end"
// "this is a msg from call back"
// "this is a msg from call back1"

Più Runtime in comunicazione tra loro

Un web worker oppure un iframe cross-origin hanno i loro stack, heap e coda di messaggi. Due runtime distinti possono comunicare esclusivamente attraverso il metodo postMessageQuesto metodo aggiunge il messaggio all'altro runtime se quest'ultimo è in ascolo degli eventi dei messaggi.

Non bloccante

Una proprietà molto interessante del modello event loop è che JavaScript, a differenza di molti altri linguaggi, non è mai bloccante. La gestione delle operazionei di I/O è tipicamente eseguita mediante eventi e callback, pertanto quando l'applicazione è in attesa che una query  IndexedDB restituisca il risultato oppure una richiesta di tipo XHR completi, può nel frattempo continuare a processare altre cose quali, ad esempio, gli user imput.

Esistono delle eccezioni dovuti alla legacy quali alert oppure le richieste sincrone XHR, ma è considerata una buona pratica evitarle. Attenzione: esistono anche eccezioni alle eccezioni (ma sono solitamente bachi implementativi o altro).

Tag del documento e collaboratori

 Hanno collaborato alla realizzazione di questa pagina: xpepper, mrbabbs, finvernizzi
 Ultima modifica di: xpepper,