SetImmediate vs. nextTick
Node.js версия 0.10 была выпущена сегодня и представлена setImmediate
. В API изменения документация предлагает использовать его при выполнении рекурсивных вызовов nextTick
.
Из чего MDN говорит, он кажется очень похожим на process.nextTick
.
Когда мне следует использовать nextTick
и когда следует использовать setImmediate
?
Ответы
Ответ 1
Используйте setImmediate
, если вы хотите поставить в очередь функцию за любыми обратными вызовами событий ввода-вывода, которые уже находятся в очереди событий. Используйте process.nextTick
для эффективной очереди функции во главе очереди событий, чтобы она выполнялась сразу после завершения текущей функции.
Итак, в случае, когда вы пытаетесь расстаться с длинной работой, связанной с процессором, с использованием рекурсии, теперь вы хотите использовать setImmediate
вместо process.nextTick
для очередности следующей итерации, поскольку в противном случае любые операции ввода/Вывода не будет иметь шансов работать между итерациями.
Ответ 2
В качестве иллюстрации
import fs from 'fs';
import http from 'http';
const options = {
host: 'www.stackoverflow.com',
port: 80,
path: '/index.html'
};
describe('deferredExecution', () => {
it('deferredExecution', (done) => {
console.log('Start');
setTimeout(() => console.log('TO1'), 0);
setImmediate(() => console.log('IM1'));
process.nextTick(() => console.log('NT1'));
setImmediate(() => console.log('IM2'));
process.nextTick(() => console.log('NT2'));
http.get(options, () => console.log('IO1'));
fs.readdir(process.cwd(), () => console.log('IO2'));
setImmediate(() => console.log('IM3'));
process.nextTick(() => console.log('NT3'));
setImmediate(() => console.log('IM4'));
fs.readdir(process.cwd(), () => console.log('IO3'));
console.log('Done');
setTimeout(done, 1500);
});
});
даст следующий выход
Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1
Надеюсь, это поможет понять разницу.
Ответ 3
В комментариях в ответе он явно не указывает, что nextTick смещается с Macrosemantics на Microsemantics.
до node 0.9 (когда был введен setImmediate), nextTick работал в начале следующего вызова.
так как node 0.9, nextTick работает в конце существующего вызова, тогда как setImmediate находится в начале следующего вызова
ознакомьтесь с https://github.com/YuzuJS/setImmediate для инструментов и деталей
Ответ 4
Я думаю, что я могу это проиллюстрировать довольно хорошо. Поскольку 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
В простых терминах process.NextTick() будет выполняться при следующем тике цикла события. Тем не менее, setImmediate, в основном имеет отдельную фазу, которая гарантирует, что обратный вызов, зарегистрированный в setImmediate(), будет вызван только после фазы обратного вызова и опроса IO.
Пожалуйста, обратитесь к этой ссылке для приятного объяснения:
https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c
![упрощенные события цикла событий]()
Ответ 6
Я рекомендую вам проверить DOCS раздел, посвященный для Loop, чтобы получить лучшее понимание. Оттуда взяли фрагмент:
У нас есть два вызова, которые похожи на пользователей, но их имена сбивают с толку.
По сути, имена должны быть заменены. process.nextTick() срабатывает больше, чем setImmediate(), но это артефакт прошлого, который вряд ли изменится.