Загрузка…
Загрузка…
Представьте себе загруженный ресторан (ваше приложение Node.js) с одним шеф-поваром (однопоточный движок JavaScript). Если бы шеф-повару приходилось ждать, пока закипит вода для каждого заказа (блокируя ввод-вывод), ресторан быстро бы остановился.
Вместо этого вместе с шеф-поваром работает умный менеджер ресторана (Цикл событий). Когда клиент заказывает макароны, менеджер приказывает повару запустить кипячение воды (асинхронная операция) и сразу же переходит к принятию следующего заказа или проверке других столов. Менеджер не ждет, пока вода закипит; они просто периодически проверяют, готова ли вода. Когда это произойдет, они сообщают об этом повару, который затем доедает макароны.
В Node.js:
Цикл событий Node.js — это непрерывный цикл, проверяющий наличие задач, которые необходимо выполнить. Он удаляет обратные вызовы из очереди и выполняет их, позволяя Node.js выполнять неблокирующие операции ввода-вывода, несмотря на то, что JavaScript является однопоточным. Когда Node.js выполняет операцию ввода-вывода (например, чтение файла с диска или получение данных из базы данных), он перекладывает эту операцию на ядро операционной системы или пул потоков. После завершения операции ядро или пул потоков уведомляет Node.js, а обратный вызов помещается в очередь для обработки циклом событий.
Традиционные модели серверов часто используют новый поток для каждого входящего соединения. Несмотря на эффективность, это потребляет значительные ресурсы памяти и ЦП, особенно при тысячах одновременных подключений.
Node.js с его циклом событий обрабатывает параллелизм по-другому:
Эта модель «выстрелил и забыл, затем обратный вызов» невероятно эффективна для задач, связанных с вводом-выводом, которые часто встречаются на веб-серверах.
Цикл событий — это не одна очередь; это циклический процесс, который проходит различные фазы, каждая из которых имеет свою очередь обратных вызовов. Node.js обычно перемещается между этими фазами, пока есть невыполненные задачи.
Вот упрощенное представление фаз цикла событий:
┌───────────────────────────┐
│ таймеры │
└─────────────┬─────────────┘
│
┌─────────────┴─────────────┐
│ ожидающие обратные вызовы │
└─────────────┬─────────────┘
│
┌─────────────┴─────────────┐
│ простаивать, готовиться │
└─────────────┬─────────────┘
│
┌─────────────┴─────────────┐
│ опрос │ console.log('Таймер выполнен'), 0);`
2. ### **Фаза ожидающих обратных вызовов**
* **Цель:** Выполняет обратные вызовы ввода-вывода, которые были отложены до следующей итерации цикла.
* **Как это работает.** На этом этапе обрабатываются определенные системные ошибки, например ошибки TCP, возникшие во время предыдущей итерации цикла событий. Код уровня приложения реже взаимодействует непосредственно с этим этапом.
3. ### **Простой, этап подготовки**
* **Цель:** Внутренний для Node.js.
* **Как это работает.** Используется для внутренних операций и оптимизации Node.js. Обычно вы не будете взаимодействовать с этим этапом непосредственно в коде приложения.
4. ### **Фаза опроса (Сердцебиение)**
* **Цель:** Это самый важный этап. Он извлекает новые события ввода-вывода и выполняет их обратные вызовы. Он также контролирует, когда блокировать и ждать новых событий ввода-вывода.
* **Как это работает:**
* **Проверка новых событий ввода-вывода.** Node.js ищет события ввода-вывода (например, чтение файла, выполнение сетевого запроса, поступление данных в сокет).
* **Выполнение обратных вызовов ввода-вывода.** При наличии событий выполняются связанные с ними обратные вызовы.
* **
`setImmediate()`
планирование:** Если
`setImmediate()`
обратные вызовы ставятся в очередь, цикл событий автоматически перейдет в
`check`
фаза *после* выполнения любых готовых обратных вызовов ввода-вывода в этом
`poll`
фаза.
* **Блокировка.** Если нет таймеров немедленного запуска и нет
`setImmediate()`
обратные вызовы, цикл может заблокироваться здесь и ждать поступления новых событий ввода-вывода.
5. ### **Проверка фазы**
* **Цель:** Выполняет обратные вызовы, запланированные
`setImmediate()`
.
* **Как это работает:** Как только
`poll`
фаза пуста от входящего ввода-вывода, если есть обратные вызовы, поставленные в очередь
`setImmediate()`
, их всех здесь казнят.
* **Пример:**
`setImmediate(() => console.log('Immediate done'));`
6. ### **Закрытие фазы обратных вызовов**
* **Цель:** Выполняет обратные вызовы для событий закрытия.
* **Как это работает:** обрабатывает такие вещи, как
`socket.on('close', ...)`
. Например, если сокет или ручка внезапно закрываются, это
`close`
На этом этапе будет выполнен обратный вызов события.
---
## Очереди микрозадач:
`process.nextTick()`
и обещания
Прежде чем погрузиться в
`process.nextTick()`
и
`setImmediate()`
, важно понимать концепцию **микрозадач** (или «очереди заданий»). Хотя приведенные выше этапы представляют собой основные очереди макрозадач цикла событий, микрозадачи имеют более высокий приоритет.
Подумайте об этом так: после того, как движок JavaScript завершил выполнение текущего сценария или обратного вызова одной из фаз цикла событий, он не переходит сразу к *следующей фазе*. Сначала он проверяет и очищает **очередь микрозадач**.
## Итог
Ключевой вывод для интервью: что такое цикл событий Node.js?