Я думаю, что я могу проиллюстрировать это довольно красиво. Так как nextTick
вызывается в конце текущей операции, вызов его рекурсивно может закончиться блокировкой цикла события от продолжения. setImmediate
решает это, активируя фазу проверки цикла событий, позволяя продолжить цикл событий.
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
Источник: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
Обратите внимание, что фаза проверки сразу после этапа опроса. Это связано с тем, что наиболее часто встречаются фаны опроса и обратные вызовы ввода-вывода, и ваши вызовы будут выполняться до setImmediate
. Поэтому в идеале большинство этих вызовов на самом деле будут довольно быстрыми, а не так быстро, как nextTick
, который проверяется после каждой операции и технически существует вне цикла событий.
Давайте посмотрим на небольшой пример разницы между setImmediate
и process.nextTick
:
function step(iteration) {
if (iteration === 10) return;
setImmediate(() => {
console.log(`setImmediate iteration: ${iteration}`);
step(iteration + 1); // Recursive call from setImmediate handler.
});
process.nextTick(() => {
console.log(`nextTick iteration: ${iteration}`);
});
}
step(0);
Скажем, мы просто запустил эту программу и пошагового первой итерации цикла событий.Он будет вызывать функцию step
с нулевой итерацией. Затем он зарегистрирует два обработчика, один для setImmediate
и один для process.nextTick
. Затем мы рекурсивно вызываем эту функцию из обработчика setImmediate
, который будет работать в следующей фазе проверки. Обработчик nextTick
будет работать в конце текущей операции, прерывая цикл событий, поэтому, несмотря на то, что он был зарегистрирован вторым, он будет фактически запускаться первым.
Порядок заканчивается время: nextTick
пожаров, как текущая операция заканчивается, начинается следующий цикл событий, обычные фазы цикла событий выполнения, setImmediate
пожаров и рекурсивно вызывают нашу step
функции, чтобы начать процесс заново. Текущая операция заканчивается, nextTick
пожаров и т.д.
Выход выше код будет:
nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9
Теперь давайте перейдем наш рекурсивный вызов step
в наш nextTick
обработчик вместо setImmediate
.
function step(iteration) {
if (iteration === 10) return;
setImmediate(() => {
console.log(`setImmediate iteration: ${iteration}`);
});
process.nextTick(() => {
console.log(`nextTick iteration: ${iteration}`);
step(iteration + 1); // Recursive call from nextTick handler.
});
}
step(0);
Теперь, когда мы переместили рекурсивный вызов step
в nextTick
обработчик вещей будет вести себя в другом порядке. Наша первая итерация цикла событий запускается и вызывает step
регистрацию обработчика setImmedaite
, а также обработчик nextTick
. После завершения текущей операции наши обработчики обработчика nextTick
, которые рекурсивно набирают step
и регистрируют другой обработчик setImmediate
, а также другой обработчик nextTick
. Поскольку обработчик nextTick
срабатывает после текущей операции, регистрация обработчика nextTick
в обработчике nextTick
приведет к тому, что второй обработчик будет запущен сразу же после завершения текущей операции обработчика. Обработчики nextTick
будут продолжать стрельбу, предотвращая непрерывность текущего цикла событий. Мы проверим всех наших обработчиков nextTick
, прежде чем мы увидим один огненный обработчик setImmediate
.
Выход выше кода заканчивается время:
nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9
Обратите внимание, что если бы мы не прервали рекурсивный вызов и прерванное его после 10 итераций то nextTick
вызовов будут держать рекурсии и никогда не позволяя цикл событий продолжить к следующему этапу. Так как nextTick
может блокироваться при использовании рекурсивно, тогда как setImmediate
будет срабатывать в следующем цикле событий, а другой обработчик setImmediate
изнутри не будет прерывать текущий цикл событий вообще, позволяя ему продолжать выполнение фаз цикла событий как обычно ,
Надеюсь, что это поможет!
PS - Я согласен с другими комментаторами в том, что имена двух функций могут быть легко заменены, так как nextTick
звучит так, как будто он загорается в следующем цикле событий, а не в конце текущего, а конец текущего цикл является более «немедленным», чем начало следующего цикла. Ну, это то, что мы получаем по мере созревания API, и люди зависят от существующих интерфейсов.
Есть 5 пунктов об этом изменении в блоге http://blog.nodejs.org/2013/03/11/node -v0-10-0-stable/ – mak
Из тестов производительности выглядит так: 'nextTick' быстрее, чем' setImmediate' при больших вычислениях. – 2014-06-02 20:13:29
Для записи я сначала прочитал эти пять абзацев и до сих пор оставался в этом вопросе, когда на самом деле я ничего не понял. Принятый ответ гораздо более краток и фактически описывает, что «setImmediate» делает более подробно. – Chev