Come funziona setTimeout in Node.JS?


112

Immagino che una volta eseguito sia in coda, ma in coda c'è qualche garanzia che verrà richiamato esattamente dopo X millisecondi? O altri compiti pesanti più in alto nella coda lo ritarderanno?


14
Nessun sistema operativo non in tempo reale renderà mai possibile la garanzia di una seria precisione. Ogni sorta di cose nel sistema possono (e lo faranno) intralciare il meccanismo del timer.
Pointy

Risposte:


174

La semantica di setTimeout è più o meno la stessa di un browser web: il timeout arg è un numero minimo di ms da attendere prima dell'esecuzione, non una garanzia. Inoltre, passare 0, un non numero o un numero negativo, farà attendere un numero minimo di ms. In Node, questo è 1 ms, ma nei browser può arrivare fino a 50 ms.

La ragione di ciò è che non vi è alcuna prelazione di JavaScript da JavaScript. Considera questo esempio:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

Il flusso qui è:

  1. programmare il timeout per 100 ms.
  2. occupato per 5000 ms.
  3. tornare al ciclo degli eventi. controllare i timer in sospeso ed eseguire.

Se questo non fosse il caso, potresti avere un po 'di JavaScript "interrotto" un altro. Dovremmo impostare mutex e semafori e simili, per evitare che un codice come questo sia estremamente difficile da ragionare su:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

La single-threadedness dell'esecuzione JavaScript di Node rende molto più semplice lavorare con la maggior parte degli altri stili di concorrenza. Ovviamente, il compromesso è che è possibile che una parte del programma che si comporta male blocchi l'intera cosa con un ciclo infinito.

È un demone migliore da combattere rispetto alla complessità della prevenzione? Dipende.


20
Ottieni un +1 per il console.logmessaggio eccezionalmente accurato .
Finanzia la causa di Monica

Mi piace il modo in cui hai inserito il TIME in maiuscolo nella tua stringa. Ottima spiegazione !!!
Alisson

43

L'idea del non blocco è che le iterazioni del ciclo sono veloci. Quindi, per iterare per ogni tick dovrebbe essere necessario un tempo abbastanza breve in modo che setTimeout sia accurato con una precisione ragionevole (off forse <100 ms circa).

In teoria però hai ragione. Se scrivo un'applicazione e blocco il segno di spunta, setTimeouts verrà ritardato. Quindi, per rispondere alla tua domanda, chi può assicurare che setTimeouts venga eseguito in tempo? Scrivendo codice non bloccante, puoi controllare il grado di accuratezza fino a quasi ogni ragionevole grado di accuratezza.

Finché javascript è "single-threaded" in termini di esecuzione del codice (esclusi web worker e simili), ciò accadrà sempre. La natura a thread singolo è un'enorme semplificazione nella maggior parte dei casi, ma per avere successo richiede l'idioma non bloccante.

Prova questo codice nel tuo browser o nel nodo e vedrai che non c'è garanzia di accuratezza, al contrario, il setTimeout sarà molto in ritardo:

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

A meno che l'interprete non ottimizzi il ciclo (cosa che non fa su Chrome), otterrai qualcosa a migliaia. Rimuovi il cappio e vedrai che sono 500 sul naso ...


9

L'unico modo per garantire che il codice venga eseguito è posizionare la logica setTimeout in un processo diverso.

Usa il modulo del processo figlio per generare un nuovo programma node.js che fa la tua logica e passa i dati a quel processo attraverso una sorta di flusso (forse tcp).

In questo modo, anche se nel processo principale è in esecuzione un codice di blocco lungo, il processo figlio si è già avviato e ha inserito un setTimeout in un nuovo processo e in un nuovo thread e verrà quindi eseguito quando previsto.

Ulteriori complicazioni sono a livello hardware in cui si hanno più thread in esecuzione quindi processi e quindi il cambio di contesto causerà ritardi (molto minori) rispetto ai tempi previsti. Questo dovrebbe essere trascurabile e, se è importante, devi considerare seriamente cosa stai cercando di fare, perché hai bisogno di una tale precisione e che tipo di hardware alternativo in tempo reale è disponibile per svolgere il lavoro.

In generale, l'utilizzo di processi figlio e l'esecuzione di applicazioni su più nodi come processi separati insieme a un bilanciatore del carico o all'archiviazione dei dati condivisa (come redis) è importante per ridimensionare il codice.


9

setTimeoutè una specie di Thread , contiene un'operazione per un dato tempo ed esegue.

setTimeout(function,time_in_mills);

qui il primo argomento dovrebbe essere un tipo di funzione; ad esempio, se vuoi stampare il tuo nome dopo 3 secondi, il tuo codice dovrebbe essere qualcosa come di seguito.

setTimeout(function(){console.log('your name')},3000);

Il punto chiave da ricordare è che qualunque cosa tu voglia fare usando il setTimeoutmetodo, fallo all'interno di una funzione . Se vuoi chiamare qualche altro metodo analizzando alcuni parametri, il tuo codice dovrebbe apparire come di seguito:

setTimeout(function(){yourOtherMethod(parameter);},3000);

8

setTimeout(callback,t)viene utilizzato per eseguire il callback dopo almeno t millisecondi . Il ritardo effettivo dipende da molti fattori esterni come la granularità del timer del sistema operativo e il carico del sistema.

Quindi, c'è la possibilità che venga chiamato leggermente dopo il tempo impostato, ma non verrà mai chiamato prima.

Un timer non può durare più di 24,8 giorni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.