NodeJS - setTimeout (fn, 0) vs setImmediate (fn)


Risposte:


72

setTimeout è semplicemente come chiamare la funzione dopo che il ritardo è terminato. Ogni volta che una funzione viene chiamata, non viene eseguita immediatamente, ma messa in coda in modo che venga eseguita dopo che tutti i gestori di eventi in esecuzione e attualmente in coda terminano per primi. setTimeout (, 0) significa essenzialmente eseguire dopo che tutte le funzioni correnti nella coda attuale sono state eseguite. Non è possibile fornire garanzie su quanto tempo potrebbe richiedere.

setImmediate è simile a questo proposito tranne per il fatto che non usa la coda di funzioni. Controlla la coda dei gestori di eventi I / O. Se tutti gli eventi I / O nell'istantanea corrente vengono elaborati, esegue la richiamata. Li mette in coda immediatamente dopo l'ultimo gestore I / O un po 'come process.nextTick. Quindi è più veloce.

Inoltre (setTimeout, 0) sarà lento perché controllerà il timer almeno una volta prima dell'esecuzione. A volte può essere due volte più lento. Ecco un punto di riferimento.

var Suite = require('benchmark').Suite
var fs = require('fs')

var suite = new Suite

suite.add('deffered.resolve()', function(deferred) {
  deferred.resolve()
}, {defer: true})

suite.add('setImmediate()', function(deferred) {
  setImmediate(function() {
    deferred.resolve()
  })
}, {defer: true})

suite.add('setTimeout(,0)', function(deferred) {
  setTimeout(function() {
    deferred.resolve()
  },0)
}, {defer: true})

suite
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})

Produzione

deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)

Il primo dà un'idea delle chiamate possibili più veloci. Puoi controllare tu stesso se setTimeout viene chiamato la metà delle volte di altri. Ricorda anche che setImmediate si adatterà alle chiamate del tuo filesystem. Quindi sotto carico funzionerà meno. Non credo che setTimeout possa fare di meglio.

setTimeout è un modo non invadente di chiamare le funzioni dopo un po 'di tempo. È proprio come nel browser. Potrebbe non essere adatto per il lato server (pensa perché ho usato benchmark.js non setTimeout).


3
È importante notare che setTimeout è soggetto a un ritardo forzato di almeno quattro millisecondi se nidificato cinque volte. vedi specifiche html
Jack Allan

Questa fonte (dall'altra risposta) sembra confutare alcune delle affermazioni qui: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev

17

Un ottimo articolo su come funziona il ciclo di eventi e cancella alcune idee sbagliate. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Citando l'articolo:

setImmediatei callback vengono chiamati dopo che i callback della coda I / O sono terminati o scaduti. setImmediate callback vengono inseriti in Check Queue, che vengono elaborati dopo I / O Queue.

setTimeout(fn, 0)i callback vengono inseriti in Timer Queue e verranno chiamati dopo i callback I / O e dopo i callback Check Queue. Come ciclo di eventi, elabora prima la coda del timer in ogni iterazione, quindi quale verrà eseguita per prima dipende da quale fase è il ciclo di eventi.


La coda setTimeout viene elaborata prima dei callback di I / O. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
umano

4

setImmediate () serve a pianificare l'esecuzione immediata del callback dopo i callback degli eventi I / O e prima di setTimeout e setInterval.

setTimeout () serve per pianificare l'esecuzione di una richiamata una tantum dopo un ritardo di millisecondi.

Questo è ciò che dicono i documenti.

setTimeout(function() {
  console.log('setTimeout')
}, 0)

setImmediate(function() {
  console.log('setImmediate')
})

Se esegui il codice precedente, il risultato sarà come questo ... anche se il documento corrente afferma che "Per pianificare l'esecuzione" immediata "del callback dopo i callback degli eventi I / O e prima di setTimeout e setInterval." ..

Risultato..

setTimeout

setImmediate

Se racchiudi il tuo esempio in un altro timer, stampa sempre setImmediate seguito da setTimeout.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);

Quindi quando preferirai uno sull'altro?
Shlomi Schwartz

23
Non hai spiegato perché accade ciò che hai mostrato. Questa risposta non mi è stata utile.
Clint Eastwood

3
@Savannah Nel tuo primo risultato, spiega perché setTimeout è stato eseguito prima di setImmediate
Agus Syahputra


1
SetImmediate non verrà eseguito prima di setTimeout e setInterval tutte le volte
Midhun GS

2

usa sempre setImmediate, a meno che tu non sia veramente sicuro di averne bisogno setTimeout(,0)(ma non riesco nemmeno a immaginare, per cosa). setImmediateil callback verrà quasi sempre eseguito prima setTimeout(,0), tranne quando viene chiamato al primo tick e al setImmediatecallback.


1
Direi che il motivo principale per utilizzare setTimeout invece di setImmediate è che il codice deve essere eseguito da browser che non hanno implementato setImmediate. Anche allora, puoi semplicemente creare uno spessore.
Gregory Magarshak

9
Questo è un consiglio malsano. Se tutto chiede di andare per primo, le caratteristiche prestazionali emergenti dell'esecuzione asincrona saranno inutili rispetto alla coda alla fine. setTimeoutdovrebbe essere il go-to, con setImmediateusato solo quando dimostrato di essere necessario.
Rich Remer

1

Totalmente insoddisfatto delle risposte fornite. Ho pubblicato quello che penso sia una risposta migliore qui: https://stackoverflow.com/a/56724489/5992714

Domande è un possibile duplicato di Perché il comportamento di setTimeout (0) e setImmediate () è indefinito quando viene utilizzato nel modulo principale?


1
Si prega di non pubblicare esattamente la stessa risposta a due domande. Se le domande sono diverse, adattare la risposta a ciascuna. Se sono uguali, contrassegna o vota per chiuderne uno come duplicato.
Tom Zych,

@ TomZych ha notato.
umano

0

Penso che la risposta di Navya S non sia corretta, ecco il mio codice di prova:

let set = new Set();

function orderTest() {
  let seq = [];
  let add = () => set.add(seq.join());
  setTimeout(function () {
    setTimeout(function () {
      seq.push('setTimeout');
      if (seq.length === 2) add();
    }, 0);

    setImmediate(function () {
      seq.push('setImmediate');
      if (seq.length === 2) add();
    });
  }, 10);
}

// loop 100 times
for (let i = 0; i < 100; i++) {
  orderTest();
}

setTimeout(() => {
  // will print one or two items, it's random
  for (item of set) {
    console.log(item);
  }
}, 100);

Le spiegazioni sono qui


0

setTimeout (fn, 0) può essere utilizzato per impedire il blocco del browser durante un aggiornamento massiccio. ad esempio in websocket.onmessage, potresti avere modifiche html e se i messaggi continuano ad arrivare, il browser potrebbe bloccarsi quando usi setImmidiate


0

Per capirli a fondo, una volta passare attraverso le fasi del ciclo di eventi.

SetImmediate: viene eseguito nella fase di "verifica". La fase di controllo viene richiamata dopo la fase di I / O.

SetTimeOut: viene eseguito nella fase "timer". La fase del timer è la prima fase ma viene richiamata dopo la fase I / O e dopo il Check fase di .

Per ottenere l'output in modo deterministico, dipenderà da quale fase è il ciclo di eventi; di conseguenza, possiamo usare la funzione su due.


-5

usa setImmediate () per non bloccare il ciclo di eventi. La richiamata verrà eseguita sul ciclo di eventi successivo, non appena quello corrente è terminato.

usa setTimeout () per ritardi controllati. La funzione verrà eseguita dopo il ritardo specificato. Il ritardo minimo è di 1 millisecondo.

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.