У чому різниця між process.nextTick() та setImmediate()?
process.nextTick() vs setImmediate()
Обидва використовуються для планування асинхронних зворотних викликів у Node.js, але вони працюють на різних етапах циклу подій і мають різні пріоритети.
process.nextTick()
Виконується одразу після завершення поточної операції, перед тим як цикл подій перейде до наступного етапу. Має найвищий пріоритет серед усіх механізмів асинхронного планування.
console.log('1 - початок');
process.nextTick(() => {
console.log('2 - nextTick');
});
console.log('3 - кінець');
// Вихід:
// 1 - початок
// 3 - кінець
// 2 - nextTickОсновні характеристики:
- Виконується перед будь-якими I/O подіями або таймерами
- Виконується в мікротасковій черзі (так само, як і виконані Promises)
- Рекурсивний
nextTickможе призвести до голодування I/O — будьте обережні!
// ⚠️ Це призведе до голодування I/O — зворотний виклик виконується вічно
function recursiveNextTick() {
process.nextTick(recursiveNextTick);
}
recursiveNextTick();
// setTimeout, setImmediate, I/O НІКОЛИ не спрацюютьsetImmediate()
Виконується на наступній ітерації циклу подій, зокрема на етапі перевірки — після завершення етапу опитування I/O.
console.log('1 - початок');
setImmediate(() => {
console.log('2 - setImmediate');
});
console.log('3 - кінець');
// Вихід:
// 1 - початок
// 3 - кінець
// 2 - setImmediateОсновні характеристики:
- Виконується на етапі перевірки циклу подій
- Не призводить до голодування I/O — завжди спочатку віддає перевагу очікуючому I/O
- Рекомендується для відкладення роботи на наступну ітерацію
Порівняння боком до боку
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('Promise'));
// Вихід (завжди):
// nextTick
// Promise
// setImmediateПорядок пріоритету циклу подій
| Пріоритет | Механізм | Черга |
|---|---|---|
| 1 (найвищий) | process.nextTick() | Мікротаск |
| 2 | Promise.then() | Мікротаск |
| 3 | setTimeout(fn, 0) | Фаза таймерів |
| 4 | setImmediate() | Фаза перевірки |
Усередині зворотного виклику I/O
Коли викликається всередині зворотного виклику I/O, setImmediate завжди виконується перед setTimeout:
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
});
// Вихід (завжди):
// setImmediate
// setTimeoutКоли використовувати що?
| Сценарій використання | Рекомендація |
|---|---|
| Має виконуватися перед будь-яким I/O | process.nextTick() |
| Відкласти на наступну ітерацію циклу подій | setImmediate() |
| Після завершення I/O | setImmediate() |
| Випускати події після конструктора | process.nextTick() |
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {
constructor() {
super();
// Випустити після повернення конструктора, щоб слухачі могли підключитися
process.nextTick(() => {
this.emit('ready');
});
}
}
const emitter = new MyEmitter();
emitter.on('ready', () => console.log('готово!'));
// Працює! 'готово!' виводитьсяНайкраща практика: Використовуйте
setImmediate()за замовчуванням. Залиштеprocess.nextTick()для випадків, коли вам потрібно виконати код перед будь-яким I/O, і уникайте рекурсивних викликівnextTick, щоб запобігти голодуванню I/O.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.