Node.js - Цикл событий: Раскрытие магии за асинхронным JavaScript
Здравствуйте, будущие кодировщики! Сегодня мы отправимся в увлекательное путешествие в сердце Node.js - Цикл событий. Не волнуйтесь, если вы никогда не писали ни строчки кода; я буду вашим доброжелательным гидом по этому fascинирующему миру. К концу этого учебника вы поймете, как Node.js manages чтобы сделать так много вещей одновременно, как вы жонглируете домашним заданием, Netflix и отправкой сообщений своим друзьям!
Что такое Цикл событий?
Представьте, что вы шеф-повар в忙ном ресторане. У вас сразу готовятся несколько блюд, тикают таймеры, и поступают заказы. Как вы справляетесь со всем этим, не поджарив食物 или не заставляя клиентов ждать? Это то, что делает Цикл событий для Node.js!
Цикл событий похож на главного шеф-повара, который постоянно проверяет, что требует внимания и обеспечивает бесперебойную работу. Это secret sauce, который позволяет Node.js выполнять неблокирующие операции ввода-вывода, несмотря на то, что JavaScript является однониточным.
Основные концепции
Прежде чем мы углубимся, давайте familiarize ourselves с некоторыми основными концепциями:
- Однониточный: JavaScript работает на одной нити, что означает, что он может делать только одно дело за раз.
- Неблокирующий: Node.js может обрабатывать несколько операций, не дожидаясь завершения каждой из них перед переходом к следующей.
- Асинхронный: Задачи могут быть начаты сейчас и завершены позже, позволяя другому коду работать в это время.
Как работает Цикл событий?
Давайте разберем Цикл событий наdigestible шаги:
- Выполнение синхронного кода в стеке вызовов
- Проверка таймеров (setTimeout, setInterval)
- Проверка pending I/O операций
- Выполнение callbacks setImmediate
- Обработка событий 'close'
Теперь давайте посмотрим это в действии с некоторыми примерами кода!
Пример 1: Синхронный vs. Асинхронный код
console.log("First");
setTimeout(() => {
console.log("Second");
}, 0);
console.log("Third");
Что вы думаете, какой будет вывод? Давайте разберем это:
- "First" выводится немедленно.
- setTimeout встречается, но вместо ожидания, Node.js устанавливает таймер и продолжает.
- "Third" выводится.
- Цикл событий проверяет завершенные таймеры и выполняет callback, выводя "Second".
Вывод:
First
Third
Second
Удивлены? Это демонстрирует, как Node.js обрабатывает асинхронные операции, не блокируя основную нить.
Пример 2: Множественные таймеры
setTimeout(() => console.log("Timer 1"), 0);
setTimeout(() => console.log("Timer 2"), 0);
setTimeout(() => console.log("Timer 3"), 0);
console.log("Hello from the main thread!");
В этом примере мы устанавливаем несколько таймеров с задержкой 0 миллисекунд. Однако Цикл событий все равно обработает их после завершения основной нити.
Вывод:
Hello from the main thread!
Timer 1
Timer 2
Timer 3
Фазы Цикла событий
Теперь, когда мы видели Цикл событий в действии, давайте рассмотрим его фазы более подробно:
1. Фаза таймеров
Эта фаза выполняет callbacks, запланированные setTimeout() и setInterval().
setTimeout(() => console.log("I'm a timer!"), 100);
setInterval(() => console.log("I repeat every 1 second"), 1000);
2. Фаза pending callbacks
Здесь Цикл событий выполняет I/O callbacks, отложенные до следующей итерации цикла.
3. Фаза Idle, Prepare
Для внутреннего использования. Здесь нет ничего интересного!
4. Фаза Poll
Извлекает новые I/O события и выполняет related callbacks.
const fs = require('fs');
fs.readFile('example.txt', (err, data) => {
if (err) throw err;
console.log(data);
});
5. Фаза Check
setImmediate() callbacks вызываются здесь.
setImmediate(() => console.log("I'm immediate!"));
6. Фаза Close Callbacks
Some close callbacks, например, socket.on('close', ...), обрабатываются здесь.
Объединяем все вместе
Давайте создадим более сложный пример, который использует различные аспекты Цикла событий:
const fs = require('fs');
console.log("Start");
setTimeout(() => console.log("Timeout 1"), 0);
setImmediate(() => console.log("Immediate 1"));
fs.readFile('example.txt', (err, data) => {
console.log("File read complete");
setTimeout(() => console.log("Timeout 2"), 0);
setImmediate(() => console.log("Immediate 2"));
});
console.log("End");
Порядок выполнения может удивить вас:
- "Start" и "End" выводятся немедленно.
- Первый setTimeout и setImmediate ставятся в очередь.
- Операция чтения файла начинается.
- Цикл событий начинает свои итерации:
- Выполняется callback первого setTimeout.
- Выполняется callback первого setImmediate.
- Когда чтение файла завершается, его callback выполняется.
- Внутри callback чтения файла еще один setTimeout и setImmediate ставятся в очередь.
- Второй setImmediate выполняется перед вторым setTimeout.
Общие методы Цикла событий
Вот таблица общих методов, связанных с Циклом событий, в Node.js:
Метод | Описание |
---|---|
setTimeout(callback, delay) | Выполняет callback после delay миллисекунд |
setInterval(callback, interval) | Выполняет callback repetitively каждый interval миллисекунд |
setImmediate(callback) | Выполняет callback на следующей итерации Цикла событий |
process.nextTick(callback) | Добавляет callback в "next tick queue", который обрабатывается после завершения текущей операции |
Заключение
Поздравляю! Вы только что сделали свои первые шаги в fascинирующем мире Node.js и его Цикла событий. Помните, как обучение езде на велосипеде, овладение асинхронной программированием требует практики. Не отчаивайтесь, если это не сразу срабатывает - продолжайте экспериментировать, и скоро вы будете писать неблокирующий код как профессионал!
Заканчивая, вот забавная аналогия: подумайте о Цикле событий как о карусели. Разные задачи (например, таймеры, I/O операции и immediate callbacks) resemble дети, пытающиеся сесть. Цикл событий продолжает вращаться, picking up и dropping off задачи в определенном порядке, обеспечивая, чтобы каждый получил turn без остановки rides.
Продолжайте программировать, stay curious, и помните - в мире Node.js, терпение не просто добродетель, это callback!
Credits: Image by storyset