NodeJS - setTimeout (fn, 0) против setImmediate (fn)

Ответы:

71

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 вдвое реже, чем other. Также помните, что setImmediate будет адаптироваться к вызовам вашей файловой системы. Так что под нагрузкой он будет работать меньше. Я не думаю, что setTimeout может стать лучше.

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

user568109
источник
3
Важно отметить, что setTimeout подвергается принудительной задержке не менее четырех миллисекунд, если вложен пять раз. см. спецификацию html
Джек Аллан
Этот источник (из другого ответа), похоже, опровергает некоторые утверждения здесь: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Дмитрий Зайцев
17

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

Цитирование статьи:

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

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

Аман Гупта
источник
Очередь setTimeout обрабатывается перед обратными вызовами ввода-вывода. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
human
6

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);
Навя С
источник
Итак, когда вы предпочтете одно другому?
Шломи Шварц
21
Вы не объяснили, почему происходит то, что вы показали. Этот ответ мне не пригодился.
Клинт Иствуд,
3
@Savannah В своем первом результате объясните, почему setTimeout выполняется первым до setImmediate
Агус Сяхпутра
2
@AgusSyahputra Проверьте это: github.com/nodejs/node-v0.x-archive/issues/25788
Родриго Бранас,
1
SetImmediate не будет выполняться перед setTimeout и setInterval все время
Mithun GS
2

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

вкурчаткин
источник
1
Я бы сказал, что основная причина использования setTimeout вместо setImmediate заключается в том, что ваш код должен выполняться браузерами, в которых не реализован setImmediate. Даже тогда вы можете просто создать прокладку.
Грегори Магаршак
9
Это необоснованный совет. Если все сначала требует выполнения, возникающие характеристики производительности асинхронного выполнения будут ненужными по сравнению с постановкой в ​​очередь в конце. setTimeoutследует setImmediateиспользовать только тогда, когда показано, что это необходимо.
Рич Ремер
1

Совершенно не удовлетворен предоставленными ответами. Я опубликовал здесь то, что, по моему мнению, лучше: qaru.site/questions/435 / ...

Вопросы - это возможный дубликат вопроса Почему поведение setTimeout (0) и setImmediate () не определено при использовании в основном модуле?

человек
источник
1
Пожалуйста, не публикуйте одинаковые ответы на два вопроса. Если вопросы разные, ответьте на каждый из них. Если они совпадают, отметьте одно из них как дубликат или проголосуйте за него.
Tom Zych
@TomZych отметил.
human
0

Я думаю, что ответ 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's random
  for (item of set) {
    console.log(item);
  }
}, 100);

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

笑笑 十年
источник
0

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

Лиор Гольдемберг
источник
0

Чтобы понять их глубоко, пожалуйста, однажды пройдите фазы цикла событий.

SetImmediate: выполняется на этапе «проверки». Проверка фаза называется после фазы I / O.

SetTimeOut: выполняется в фазе "таймера". Таймер фаза является первой фазой , но вызывается после I / O фазы, а также Проверка фазы.

Чтобы получить результат детерминированным образом, это будет зависеть от того, на какой фазе находится цикл событий; соответственно, мы можем использовать функцию из двух.

Каника Шарма
источник
-4

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

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

Андрас
источник