В чем разница между этими двумя, и когда я буду использовать один над другим?
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
Ответ 7
Абсолютно недоволен предоставленными ответами. Я отправил то, что я думаю, лучшие ответы здесь: fooobar.com/questions/1684657/...
Вопросы являются возможной копией Почему поведение setTimeout (0) и setImmediate() не определено при использовании в основном модуле?
Ответ 8
используйте setImmediate(), чтобы не блокировать цикл события. Обратный вызов будет запущен в следующем цикле событий, как только будет выполнен текущий.
используйте setTimeout() для контролируемых задержек. Функция будет работать после указанной задержки. Минимальная задержка составляет 1 миллисекунду.