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

В чем разница между этими двумя, и когда я буду использовать один над другим?

Ответ 1

setTimeout просто как вызов функции после задержки. Всякий раз, когда вызывается функция, она не выполняется сразу, а ставится в очередь, так что она выполняется после того, как все выполняющиеся и находящиеся в очереди обработчики событий заканчиваются первыми. setTimeout (, 0) по существу означает выполнение после того, как все текущие функции в текущей очереди будут выполнены. Мы не можем дать никаких гарантий относительно того, сколько времени это займет.

setImmediate аналогичен в этом отношении за исключением того, что он не использует очередь функций. Проверяет очередь обработчиков событий ввода/вывода. Если все события ввода/вывода в текущем снимке обрабатываются, выполняется обратный вызов. Он ставит их в очередь сразу после последнего обработчика ввода-вывода, что-то вроде process.nextTick. Так что это быстрее.

Также (setTimeout, 0) будет медленным, потому что он проверит таймер хотя бы один раз перед выполнением. Иногда это может быть в два раза медленнее. Вот эталон.

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

Выход

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)

Первый дает представление о самых быстрых звонках. Вы можете проверить, вызывается ли setTimeout в два раза чаще, чем другие. Также помните, что setImmediate подстраивается под вызовы вашей файловой системы. Так что под нагрузкой он будет работать меньше. Я не думаю, что setTimeout может работать лучше.

setTimeout - это ненавязчивый способ вызова функций через некоторое время. Это так же, как в браузере. Возможно, он не подходит для серверной части (подумайте, почему я использовал benchmark.js, а не setTimeout).

Ответ 2

Отличная статья о том, как работает цикл обработки событий и устраняет некоторые заблуждения. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Цитирую статью:

setImmediate вызовы setImmediate вызываются после завершения или setImmediate обратных вызовов очереди ввода-вывода. Обратные вызовы setImmediate помещаются в очередь проверки, которые обрабатываются после очереди ввода-вывода.

Обратные вызовы setTimeout(fn, 0) помещаются в очередь таймеров и будут вызываться после обратных вызовов ввода-вывода, а также обратных вызовов проверки очереди. В качестве цикла обработки событий очередь таймера обрабатывается первой на каждой итерации, поэтому то, какая из них будет выполняться первой, зависит от того, какой фазовый цикл имеет место.

Ответ 3

setImmediate() - запланировать немедленное выполнение обратного вызова после обратных вызовов событий ввода-вывода и перед setTimeout и setInterval.

setTimeout() - планировать выполнение однократного обратного вызова после задержек в миллисекундах.

Это то, что говорят документы.

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

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

Если вы запустите вышеуказанный код, результат будет таким, как это... хотя в текущем документе указано, что "Назначить" немедленное "выполнение обратного вызова после обратных вызовов событий ввода-вывода и перед setTimeout и setInterval"...

Результат..

setTimeout

setImmediate

Если вы переносите свой пример в другой таймер, он всегда печатает setImmediate, за которым следует setTimeout.

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

Ответ 4

всегда используйте setImmediate, если вы не уверены, что вам нужно setTimeout(,0) (но я даже не могу представить, зачем). Обратный вызов setImmediate почти всегда будет выполняться до setTimeout(,0), за исключением случаев, когда вызывается в первом тике и в обратном вызове setImmediate.

Ответ 5

Я думаю, что ответ Navya S не правильный, вот мой тестовый код:

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 random
  for (item of set) {
    console.log(item);
  }
}, 100);

Объяснения здесь

Ответ 6

setTimeout (fn, 0) может использоваться для предотвращения зависания браузера при массовом обновлении. например, в websocket.onmessage у вас могут быть изменения html, и если сообщения продолжают поступать, браузер может зависнуть при использовании setImmidiate

Ответ 8

используйте setImmediate(), чтобы не блокировать цикл события. Обратный вызов будет запущен в следующем цикле событий, как только будет выполнен текущий.

используйте setTimeout() для контролируемых задержек. Функция будет работать после указанной задержки. Минимальная задержка составляет 1 миллисекунду.