setTimeout против setImmediate против process.nextTick
В чем разница между setTimeout(callback, 0)
а также process.nextTick(callback)
? Как насчет узла setImmediate(callback)
?
На первый взгляд кажется, что все три функции делают одно и то же — они выполняют обратный вызов после текущего цикла обработки событий, но до всего остального. Возникает естественный вопрос: почему существуют три разные функции? Проведем эксперимент:
let racer = function() {
setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
process.nextTick(() => console.log("nextTick"));
console.log("current event loop");
}
racer()
Из вывода видно, что эти обратные вызовы не выполняются в том же порядке, в котором они были написаны в исходном коде.
[Running] node "/Users/logicmason/timeouts.js"
current event loop
nextTick
timeout
immediate
[Done] exited with code=0 in 0.203 seconds
Объяснение
Первым казненным был process.nextTick
, который помещает свой обратный вызов в начало очереди событий. Он будет выполняться после текущего кода, но перед любыми событиями ввода-вывода или таймерами.
Далее идет «тайм-аут». Поскольку мы прошли setTimeout
тайм-аут равен 0, нет дополнительной принудительной задержки перед его выполнением, и он помещается в очередь таймера во время следующего цикла.
Наконец, у нас есть setImmediate
, что явно не так быстро, как следует из его названия! Его обратный вызов помещается в очередь проверки следующего цикла цикла обработки событий. Поскольку очередь проверки возникает позже, чем очередь таймера, setImmediate будет медленнее, чем setTimeout 0.
В целом цикл событий выглядит так:
timers
-> IO
-> poll
-> check
->close
-> timers
-> …
Таймеры: обратные вызовы от setInterval
или же setTimeout
обратные вызовы ввода-вывода: обратные вызовы от событий ввода/вывода
Праздный: используется узлом внутри между фазами ввода-вывода и опроса.
Опрос: получить новые события ввода/вывода
Проверять: обратные вызовы от setImmediate
выполнить здесь
Закрывать: обрабатывать закрытые соединения, такие как сокеты
Время вызова!
Что вы ожидаете от следующего кода в Node?
let racer1 = function() {
setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
process.nextTick(() => console.log("nextTick"));
}
let racer2 = function() {
process.nextTick(() => console.log("nextTick"));
setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
}
let racer3 = function() {
setImmediate(() => console.log("immediate"));
process.nextTick(() => console.log("nextTick"));
setTimeout(() => console.log("timeout"), 0);
}
racer1()
racer2()
racer3()
Это было то, что вы ожидали?
Первоначально опубликовано на Logicmason.com