2015-02-21 12 views
11

Ho letto questo articolo http://ejohn.org/blog/how-javascript-timers-work/ e come setTimeout e setInterval e di altri compiti asincroni, come scatto del tasto mi confuso un po '.SetTimeout o setInterval usano il thread per sparare?

So che JS è un singolo thread, ovvero AFAIK, tutte le funzioni di callback (a.k.a. gestori di eventi) verranno accodate ed eseguite in ordine. Tuttavia, guardare l'immagine qui sotto che ho preso da questo articolo, linkato sopra:

enter image description here

Ogni blocco rappresenta un certo lavoro, e - a circa 10ms - il timer viene licenziato. So che la sua funzione di callback è messa in coda per l'esecuzione successiva, ma come mai l'evento può essere richiamato mentre qualcosa viene già eseguito?

Forse perché setTimeout() inizia a utilizzare un thread separato per contare il tempo internamente e fuoco il suo evento di completamento?

prega di notare che io non sto parlando di sua esecuzione richiamata qui; piuttosto, sto cercando di capire come setTimeout può contare il tempo e si accende il suo completamento. So che la sua callback verrà chiamata non prima che i suoi dati parametri di tempo, ma forse più tardi, ma questo è perché il suo richiamo si accoda al secondo momento, quando il runtime trova un po 'di tempo per verificare se c'è qualcosa da eseguire nella coda.

simile a questa domanda, come mai i browser accetta nuova clicca per essere registrato, mentre - diciamo - un ciclo sta lavorando dietro le quinte al momento di utente clicca?

Se dici browser mantengono le discussioni diverse per cose diverse, allora possiamo chiamare JS nei browser single threaded?

+0

Inoltre, controllare le risposte a questa domanda: http://stackoverflow.com/questions/1663125/is-javascript-multithreaded tua domanda aggiunge un elemento interessante per la conversazione. Non so se è un duplicato anche se la domanda, di per sé, è sostanzialmente diversa – Thomas

risposta

15

JavaScript è a thread singolo, il che significa che due parti di JavaScript non verranno eseguite contemporaneamente (a meno che non si utilizzi un worker, ma ogni worker è anche a thread singolo). Ma JavaScript non è l'unica cosa in gioco quando si tratta di API dell'ambiente. Funzioni come setTimeout, setInterval e addEventListener sono implementate in modo nativo (o, at-almeno, al di fuori del single-threaded JavaScript), e le loro callback sono attivati ​​da l'ambiente, come ad esempio un browser. È l'ambiente che mette questi callback sulla coda, per essere eseguito dal motore JavaScript a thread singolo. In questo modo il browser è in grado di accettare nuovi eventi di clic da attivare, anche se sta ancora eseguendo un altro codice JavaScript. Questa è la ragione per cui JavaScript è considerato guidato dagli eventi.

+0

Quindi, su un "Non ho idea di cosa sto facendo livello" (perché non lo faccio), il browser tiene traccia di qualche altra "roba" ambientale? Puoi approfondire "esecuzione nativa" o indicarmi la giusta direzione per alcune buone letture? Molto curioso di questa roba, lo sono. – Thomas

+2

@Thomas Purtroppo non ho alcun collegamento a portata di mano, ma con "implementato in modo nativo", intendo che queste API sono implementate dall'ambiente host e non sono implementate o eseguite nel JavaScript a thread singolo, solo il callback lo è. –

+2

il browser non è necessariamente multithread, neanche; puoi facilmente implementare l'immagine mostrata nella domanda con un ciclo di eventi abbastanza standard, senza bisogno di discussioni. – Eevee

1

Allo stato attuale (ECMAScript 6), non devi preoccuparti per il cambiamento di stato a metà strada all'interno di una funzione.

Tuttavia, molte cose agiscono in background e cambiano il loro ambiente isolato, che in un secondo momento può essere inviato all'ambiente principale sotto forma di blocchi di dati. La coda di richiamata, i timer e gli operatori Web di XMLHttpRequest lo fanno tutti. Sono tutti potenzialmente eseguiti contemporaneamente (in più CPU), ma comunicano tutti con l'ambiente principale in modo sequenziale.

1

Non c'è bisogno di avere altri thread per spiegare questo comportamento. Quando un record del timer viene aggiunto alla coda, rimane semplicemente lì. Se il ciclo degli eventi ottiene nuovamente il controllo, controlla semplicemente se esiste un'attività pianificata il cui tempo è scaduto o meno.

Non è inoltre necessario un thread aggiuntivo per mantenere il tempo globale poiché questo è già stato consegnato dal sistema operativo o dall'ambiente di esecuzione.

Prendiamo ad esempio questo semplice script PhantomJS:

function longRunningTask() { 
    for(var i = 0; i < 100000; i++) { 
     var s = "", 
      s2 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 
     for(var j = 0; j < 1000; j++) { 
      s += s2; 
     } 
    } 
} 

var start = new Date().getTime(); 
console.log("begin"); 
setTimeout(function(){ 
    console.log("end timer 1s " + (new Date().getTime() - start)); 
}, 1000); 

setTimeout(function(){ 
    console.log("end timer 10s " + (new Date().getTime() - start)); 
}, 10000); 
longRunningTask(); 
console.log("end longRunningTask " + (new Date().getTime() - start)); 

setTimeout(function(){ 
    console.log("EXIT"); 
    phantom.exit(); 
}, 11000); 

che produce il seguente output:

 
begin 
end longRunningTask 5025 
end timer 1s 5029 
end timer 10s 10001 
EXIT 

Quello secondo timer solo incendi quando il controllo viene restituito al ciclo di eventi.

Problemi correlati