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

87

Qual é a diferença entre os dois e quando vou usar um em vez do outro?

Shlomi Schwartz
fonte
2
Conjunto
Benjamin Gruenbaum

Respostas:

71

setTimeout é simplesmente como chamar a função após o término do atraso. Sempre que uma função é chamada, ela não é executada imediatamente, mas enfileirada para que seja executada depois que todos os manipuladores de eventos em execução e atualmente enfileirados terminem primeiro. setTimeout (, 0) significa essencialmente executar depois que todas as funções atuais na fila atual forem executadas. Nenhuma garantia pode ser feita sobre quanto tempo isso pode levar.

setImmediate é semelhante nesse aspecto, exceto que não usa fila de funções. Ele verifica a fila de manipuladores de eventos de E / S. Se todos os eventos de E / S no instantâneo atual forem processados, ele executa o retorno de chamada. Ele os enfileira imediatamente após o último manipulador de E / S, de forma semelhante a process.nextTick. Portanto, é mais rápido.

Além disso, (setTimeout, 0) será lento porque verificará o cronômetro pelo menos uma vez antes de executar. Às vezes, pode ser duas vezes mais lento. Aqui está uma referência.

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

Resultado

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)

Primeiro dá-se uma ideia das chamadas mais rápidas possíveis. Você pode verificar se setTimeout é chamado a metade das vezes que outro. Lembre-se também de que o setImmediate se ajustará às chamadas do seu sistema de arquivos. Portanto, sob carga, o desempenho será menor. Não acho que setTimeout possa fazer melhor.

setTimeout é uma forma não intrusiva de chamar funções depois de algum tempo. É exatamente como no navegador. Pode não ser adequado para o lado do servidor (pense por que usei benchmark.js e não setTimeout).

user568109
fonte
3
É importante observar que setTimeout está sujeito a um atraso forçado de pelo menos quatro milissegundos se aninhado cinco vezes. ver especificações de html
Jack Allan
Esta fonte (da outra resposta) parece refutar algumas das afirmações aqui: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev
17

Um ótimo artigo sobre como funciona o loop de eventos e elimina alguns equívocos. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Citando o artigo:

setImmediateos retornos de chamada são chamados depois que os retornos de chamada da Fila de E / S são concluídos ou expiram. Os retornos de chamada setImmediate são colocados em Check Queue, que são processados ​​após I / O Queue.

setTimeout(fn, 0)callbacks são colocados em Timer Queue e serão chamados após callbacks de I / O, bem como callbacks Check Queue. Como loop de evento, processe a fila do cronômetro primeiro em cada iteração, de forma que qual delas será executada primeiro depende de qual loop de evento de fase é.

Aman Gupta
fonte
A fila setTimeout é processada antes dos retornos de chamada de E / S. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
humano
6

setImmediate () é para agendar a execução imediata de callback após callbacks de eventos de E / S e antes de setTimeout e setInterval.

setTimeout () é para agendar a execução de um retorno de chamada único após um atraso de milissegundos.

Isso é o que dizem os documentos.

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

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

Se você executar o código acima, o resultado será assim ... embora o documento atual indique que "Para agendar a execução" imediata "do retorno de chamada após os retornos de chamada de eventos de E / S e antes de setTimeout e setInterval." ..

Resultado..

setTimeout

setImmediate

Se você envolver seu exemplo em outro cronômetro, ele sempre imprimirá setImmediate seguido por setTimeout.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);
Navya S
fonte
Então, quando você vai preferir um ao outro?
Shlomi Schwartz
21
Você não explicou por que o que você mostrou acontece. Essa resposta não foi útil para mim.
Clint Eastwood
3
@Savannah Em seu primeiro resultado, explique por que setTimeout foi executado antes de setImmediate
Agus Syahputra
2
@AgusSyahputra Confira: github.com/nodejs/node-v0.x-archive/issues/25788
Rodrigo Branas
1
SetImmediate não será executado antes de setTimeout e setInterval todas as vezes
Mithun GS
2

use sempre setImmediate, a menos que você tenha certeza de que precisa setTimeout(,0)(mas nem consigo imaginar para quê). setImmediateo callback quase sempre será executado antes setTimeout(,0), exceto quando chamado no primeiro tick e no setImmediatecallback.

vkurchatkin
fonte
1
Eu diria que o principal motivo para usar setTimeout em vez de setImmediate é que seu código precisa ser executado por navegadores que não têm setImmediate implementado. Mesmo assim, você pode apenas criar um calço.
Gregory Magarshak,
9
Este é um conselho doentio. Se tudo pedir para ser executado primeiro, as características de desempenho emergentes da execução assíncrona serão lixo em comparação com o enfileiramento no final. setTimeoutdeve ser o ponto de partida, sendo setImmediateusado somente quando for necessário.
Rich Remer
1

Totalmente insatisfeito com as respostas fornecidas. Publiquei o que considero uma resposta melhor aqui: https://stackoverflow.com/a/56724489/5992714

Perguntas é uma possível duplicata de Por que o comportamento de setTimeout (0) e setImmediate () é indefinido quando usado no módulo principal?

humano
fonte
1
Por favor, não poste exatamente a mesma resposta para duas perguntas. Se as perguntas forem diferentes, adapte a resposta a cada uma. Se forem iguais, marque ou vote para fechar um como duplicado.
Tom Zych
@TomZych observou.
humano
0

Acho que a resposta do Navya S não está correta, aqui está o meu código de teste:

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

As explicações estão aqui

笑笑 十年
fonte
0

setTimeout (fn, 0) pode ser usado para evitar que o navegador congele em uma atualização massiva. por exemplo, em websocket.onmessage, você pode ter alterações de html e, se as mensagens continuarem chegando, o navegador pode congelar ao usar setImmidiate

Lior Goldemberg
fonte
0

Para entendê-los profundamente, passe uma vez pelas fases do loop de eventos.

SetImmediate: é executado na fase de "verificação". A fase de verificação é chamada após a fase de E / S.

SetTimeOut: É executado na fase de "cronômetro". A fase do temporizador é a primeira fase, mas é chamada após a fase de E / S , bem como a fase de verificação .

Para obter a saída de maneira determinística, dependerá de qual fase está o loop de eventos; consequentemente, podemos usar a função de dois.

Kanika Sharma
fonte
-4

use setImmediate () para não bloquear o loop de eventos. O retorno de chamada será executado no próximo loop de evento, assim que o atual for concluído.

use setTimeout () para atrasos controlados. A função será executada após o atraso especificado. O atraso mínimo é de 1 milissegundo.

Andras
fonte