NextTick vs setImmediate, визуальное объяснение
Я очень смущен различиями между nextTick и setImmediate. Я прочитал всю документацию о них в Интернете, но я до сих пор не понимаю, как они работают.
Примеры:
function log(n) { console.log(n); }
setImmediate
setImmediate(function() {
setImmediate(function() {
log(1);
setImmediate(function() { log(2); });
setImmediate(function() { log(3); });
});
setImmediate(function() {
log(4);
setImmediate(function() { log(5); });
setImmediate(function() { log(6); });
});
});
//1 2 3 4 5 6
nextTick
process.nextTick(function() {
process.nextTick(function() {
log(1);
process.nextTick(function() { log(2); });
process.nextTick(function() { log(3); });
});
process.nextTick(function() {
log(4);
process.nextTick(function() { log(5); });
process.nextTick(function() { log(6); });
});
});
//1 4 2 3 5 6
Почему эти результаты? Пожалуйста, объясните с помощью визуального или очень простого объяснения. Даже разработчики node не согласны с тем, как nextTick и setImmediate должны быть поняты людьми.
Источники:
Ответы
Ответ 1
Рассмотрим следующие два примера:
setImmediate
setImmediate(function A() {
setImmediate(function B() {
log(1);
setImmediate(function D() { log(2); });
setImmediate(function E() { log(3); });
});
setImmediate(function C() {
log(4);
setImmediate(function F() { log(5); });
setImmediate(function G() { log(6); });
});
});
setTimeout(function timeout() {
console.log('TIMEOUT FIRED');
}, 0)
// 'TIMEOUT FIRED' 1 4 2 3 5 6
// OR
// 1 'TIMEOUT FIRED' 4 2 3 5 6
nextTick
process.nextTick(function A() {
process.nextTick(function B() {
log(1);
process.nextTick(function D() { log(2); });
process.nextTick(function E() { log(3); });
});
process.nextTick(function C() {
log(4);
process.nextTick(function F() { log(5); });
process.nextTick(function G() { log(6); });
});
});
setTimeout(function timeout() {
console.log('TIMEOUT FIRED');
}, 0)
// 1 4 2 3 5 6 'TIMEOUT FIRED'
setImmediate обратные вызовы выходят из цикла событий один раз на итерацию в том порядке, в котором они были поставлены в очередь. Итак, на первой итерации цикла события выполняется обратный вызов A. Затем на второй итерации цикла события обратный вызов B запускается, затем на третьей итерации обратного вызова цикла цикла C и т.д. Это предотвращает блокировку цикла событий и позволяет другим обратным вызовам ввода-вывода или таймера (как в случае тайм-аута 0мс, который запускается на итерации 1-го или 2-го цикла).
nextTick обратные вызовы, однако, всегда запускаются сразу же после выполнения текущего кода и перед возвратом в цикл событий. В примере nextTick мы завершаем все последующие обратные вызовы nextTick, прежде чем возвращаться к циклу событий. Поскольку callback callTimeout вызывается из цикла событий, текст "TIMEOUT FIRED" не будет выводиться до тех пор, пока мы не закончим с каждым последующим обратным вызовом.
Ответ 2
Согласно документу Node.js имена этих двух функций точно поменялись местами.
setImmediate() (ЛУЧШИЙ РЕКОМЕНДУЕТСЯ)
Он запускается первым в очереди событий
process.nextTick() (ИСПОЛЬЗУЙТЕ ДЛЯ ОСОБЫХ СЛУЧАЙ, см. пример позже)
Он сразу же запускается, он в конце пишет текущий файл
Если у нас есть этот код
setTimeout(function(){
console.log('Hello world 5'); // It waiting like a normal person at a queue
}, 0);
setImmediate(function(){
console.log('Hello world 4');
// It like get to last and be take care of first
// but always after of .nextTick and before of setInterval(, 0)
});
process.nextTick(function(){
console.log('Hello world 3'); // It like be at the bottom at this file
});
console.log('Hello world 1');
console.log('Hello world 2');
Визуальное объяснение согласно вашему запросу:
![enter image description here]()
Случаи использования process.nextTick(), когда вы должны произвести событие и событие, прежде чем его обработать:
const EventEmitter = require('events');
const util = require('util');
function MyEmitter() {
EventEmitter.call(this);
// use nextTick to emit the event once a handler is assigned
process.nextTick(function () {
this.emit('event');
}.bind(this));
}
util.inherits(MyEmitter, EventEmitter);
const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
console.log('an event occurred!');
});
Посмотрите на этот видеоролик, где Филип Робертс дает нам отличное объяснение о цикле событий во время выполнения, и посмотрите на этот онлайн-отладчик Eventloop Live Test, как работает цикл событий.
Источник: https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate
Ответ 3
Я не могу воспроизвести ваши результаты для setImmediate
. Он должен быть таким же, как nextTick
(и он находится в моих тестах), поскольку в этой ситуации они делают почти то же самое. Единственным разумным объяснением этого является то, что setImmediate
как-то синхронно, но это не так.
И согласно документации NodeJS единственное реальное различие заключается в том, что несколько nextTick
могут срабатывать в одной итерации цикла (в зависимости от maxTickDepth
), а setImmediate
срабатывает один раз на итерацию.
Ответ 4
Ниже приведена лучшая ясность.
- Выполняет script после завершения текущей фазы опроса.
- Функция таймера и функции таймера являются глобальными, вы можете вызывать их без
require
.
- Он может быть очищен clearImmediate().
- Установите "немедленное" выполнение обратного вызова после обратных вызовов событий ввода-вывода перед setTimeout() и setInterval().
- Это глобальная функция процесса процесса NodeJS.
- Все обратные вызовы, переданные process.nextTick(), будут разрешены до того, как цикл события будет продолжен.
- Разрешить пользователям обрабатывать ошибки.
- Помогает снова запросить запрос до того, как цикл цикла будет продолжен.
Простой фрагмент кода.
console.log("I'm First");
setImmediate(function () {
console.log('Im setImmediate');
});
console.log("I'm Second");
process.nextTick(function () {
console.log('Im nextTick');
});
console.log("I'm Last");
/*
Output
$ node server.js
I'm First
I'm Second
I'm Last
Im nextTick
Im setImmediate
*/
Ответ 5
Я думаю, что все приведенные выше ответы устарели, потому что я постоянно получал разные ответы с текущей версией nodejs, и легко рассуждать о
var log=console.log
log(process.version)
var makeAsyncCall
if(false)
makeAsyncCall=setImmediate
else
makeAsyncCall=process.nextTick;
makeAsyncCall(function A () {
makeAsyncCall(function B() {
log(1);
makeAsyncCall(function C() { log(2); });
makeAsyncCall(function D() { log(3); });
});
makeAsyncCall(function E() {
log(4);
makeAsyncCall(function F() { log(5); });
makeAsyncCall(function G() { log(6); });
});
});
//1
//4
//2
//3
//5
//6
//in both case
После чтения https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate
давайте начнем с setImmediate
, мы должны отслеживать check queue
, потому что там находится обратный вызов setImmediate
.
Первая итерация
A
нажимается на check queue
проверить очередь: [A]
Вторая итерация
A
вытаскивается из queue
для выполнения
Во время его выполнения он помещает B
и E
в queue
, а затем A
завершает и запускает следующую итерацию
проверить очередь: [B, E]
Третья итерация
вытащите B
и нажмите C
D
проверить очередь: [E, C, D]
Четвертая итерация
вытащите E
и нажмите F
G
проверить очередь: [C, D, F, G]
Наконец
выполнить обратные вызовы в очереди последовательно
В случае nextTick
очередь работает точно так же, поэтому она дает тот же результат
Другое:
nextTickQueue будет обработан после текущей операции завершает, независимо от текущей фазы цикла события
Чтобы быть ясным, цикл событий поддерживает несколько очередей, а check queue
- только один из них, node будет решать, какую очередь использовать на основе некоторых правил
с process.nextTick
однако, он вроде обходит все правило и выполняет обратный вызов в nextTick
немедленно