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


Odpowiedzi:


72

setTimeout jest po prostu jak wywołanie funkcji po zakończeniu opóźnienia. Za każdym razem, gdy wywoływana jest funkcja, nie jest ona wykonywana natychmiast, ale umieszczana w kolejce, tak aby była wykonywana po zakończeniu wszystkich wykonujących i aktualnie umieszczonych w kolejce programów obsługi zdarzeń. setTimeout (, 0) zasadniczo oznacza wykonanie po wykonaniu wszystkich bieżących funkcji w obecnej kolejce. Nie można zagwarantować, jak długo to potrwa.

setImmediate jest pod tym względem podobna, z tą różnicą, że nie używa kolejki funkcji. Sprawdza kolejkę obsługi zdarzeń I / O. Jeśli wszystkie zdarzenia we / wy w bieżącej migawce są przetwarzane, wykonuje wywołanie zwrotne. Kolejkuje je natychmiast po ostatnim programie obsługi we / wy, podobnie jak process.nextTick. Więc to jest szybsze.

Również (setTimeout, 0) będzie wolne, ponieważ przynajmniej raz sprawdzi licznik czasu przed wykonaniem. Czasami może być dwa razy wolniejsze. Oto punkt odniesienia.

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})

Wynik

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)

Pierwsza daje wyobrażenie o możliwie najszybszych połączeniach. Możesz sam sprawdzić, czy setTimeout jest wywoływany o połowę mniej niż inne. Pamiętaj również, że setImmediate dostosuje się do wywołań twojego systemu plików. Więc pod obciążeniem będzie działać mniej. Nie sądzę, żeby setTimeout działał lepiej.

setTimeout to nieinwazyjny sposób wywoływania funkcji po pewnym czasie. Podobnie jak w przeglądarce. Może nie być odpowiedni dla serwera (pomyśl, dlaczego użyłem benchmark.js, a nie setTimeout).


3
Należy zauważyć, że metoda setTimeout podlega wymuszonemu opóźnieniu wynoszącemu co najmniej cztery milisekundy, jeśli zostanie zagnieżdżona pięć razy. zobacz specyfikację html
Jack Allan

To źródło (z innej odpowiedzi) wydaje się obalać niektóre stwierdzenia tutaj: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev

17

Świetny artykuł o tym, jak działa pętla zdarzeń i wyjaśnia niektóre nieporozumienia. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Cytując artykuł:

setImmediatewywołania zwrotne są wywoływane po zakończeniu lub przekroczeniu limitu czasu wywołań zwrotnych kolejki we / wy. setImmediate wywołania zwrotne są umieszczane w kolejce sprawdzania, które są przetwarzane po kolejce we / wy.

setTimeout(fn, 0)callbacki są umieszczane w Timer Queue i będą wywoływane po wywołaniach I / O oraz Check Queue. Jako pętla zdarzeń przetwórz kolejkę timera jako pierwszą w każdej iteracji, więc to, która z nich zostanie wykonana jako pierwsza, zależy od tego, która pętla zdarzeń fazy jest.


Kolejka setTimeout jest przetwarzana przed wywołaniami zwrotnymi we / wy. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
human

5

setImmediate () służy do planowania natychmiastowego wykonania wywołania zwrotnego po wywołaniach zwrotnych zdarzeń I / O, a przed ustawieniami setTimeout i setInterval.

setTimeout () służy do zaplanowania wykonania jednorazowego wywołania zwrotnego po upływie milisekund opóźnienia.

Tak mówią dokumenty.

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

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

Jeśli uruchomisz powyższy kod, wynik będzie taki ... mimo że w bieżącym dokumencie jest napisane, że „Aby zaplanować„ natychmiastowe ”wykonanie wywołania zwrotnego po wywołaniach zwrotnych zdarzeń we / wy, a przed ustawieniami setTimeout i setInterval.” ..

Wynik..

setTimeout

setImmediate

Jeśli umieścisz swój przykład w innym zegarze, zawsze wypisuje setImmediate, po którym następuje setTimeout.

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

Kiedy więc wolisz jedno nad drugim?
Shlomi Schwartz

23
Nie wyjaśniłeś, dlaczego dzieje się to, co pokazałeś. Ta odpowiedź nie była dla mnie przydatna.
Clint Eastwood

3
@Savannah W swoim pierwszym wyniku wyjaśnij, dlaczego setTimeout został wykonany jako pierwszy przed setImmediate
Agus Syahputra


1
SetImmediate nie zostanie wykonane przed setTimeout i setInterval cały czas
Midhun GS

2

zawsze używaj setImmediate, chyba że jesteś naprawdę pewien, że potrzebujesz setTimeout(,0)(ale nie mogę sobie nawet wyobrazić, po co). setImmediatecallback prawie zawsze będzie wykonywany wcześniej setTimeout(,0), z wyjątkiem wywołania w pierwszym tiku i podczas setImmediatecallback.


1
Powiedziałbym, że głównym powodem używania setTimeout zamiast setImmediate jest to, że twój kod musi być wykonywany przez przeglądarki, które nie mają zaimplementowanego setImmediate. Nawet wtedy możesz po prostu stworzyć podkładkę.
Gregory Magarshak

9
To nie jest rozsądna rada. Jeśli wszystko wymaga pierwszej kolejności, pojawiające się cechy wydajności wykonywania asynchronicznego staną się niepotrzebne w porównaniu z kolejkowaniem na końcu. setTimeoutpowinny być setImmediateużywane tylko wtedy, gdy okaże się to konieczne.
Rich Remer

1

Całkowicie niezadowolony z udzielonych odpowiedzi. To, co uważam za lepsze odpowiedzi, zamieściłem tutaj: https://stackoverflow.com/a/56724489/5992714

Pytania są możliwym duplikatem Dlaczego zachowanie setTimeout (0) i setImmediate () jest niezdefiniowane, gdy są używane w module głównym?


1
Nie publikuj dokładnie tej samej odpowiedzi na dwa pytania. Jeśli pytania są różne, dostosuj odpowiedź do każdego. Jeśli są takie same, oznacz je lub zagłosuj, aby zamknąć jeden jako duplikat.
Tom Zych

@TomZych zauważył.
człowiek

0

Myślę, że odpowiedź Navya S nie jest poprawna, oto mój kod testowy:

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);

Wyjaśnienia są tutaj


0

setTimeout (fn, 0) może służyć do zapobiegania zawieszaniu się przeglądarki podczas masowej aktualizacji. na przykład w websocket.onmessage, możesz mieć zmiany w html, a jeśli wiadomości będą przychodzić, przeglądarka może się zawiesić podczas używania setImmidiate


0

Aby je dogłębnie zrozumieć, proszę przejść przez fazy pętli zdarzeń.

SetImmediate: jest wykonywany w fazie „sprawdzania”. Faza sprawdzania jest wywoływana po fazie I / O.

SetTimeOut: Jest wykonywany w fazie „timera”. Faza timera jest pierwszą fazą, ale jest wywoływana po fazie I / O oraz fazie Check .

Aby uzyskać wynik w sposób deterministyczny, będzie to zależeć od fazy pętli zdarzeń; odpowiednio, możemy użyć funkcji z dwóch.


-5

użyj setImmediate (), aby nie blokować pętli zdarzeń. Wywołanie zwrotne zostanie uruchomione w następnej pętli zdarzeń, gdy tylko bieżąca zostanie wykonana.

użyj setTimeout () dla kontrolowanych opóźnień. Funkcja uruchomi się po określonym czasie. Minimalne opóźnienie to 1 milisekunda.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.