Event Loop NodeJS: Part 1
Содержание
Event Loop NodeJS
NodeJS отличается от других платформ тем, как обрабатываются события ввода/вывода, или проще I/O. NodeJS рекламируют как “Не блокирующая, событийно управляемая платформа на базе движка JavaScript V8” (да, именно от V-образного 8-цилиндрового двигателя название и было взято).
Что все это значит? Что значит “не блокирующий” и “событийно управляемый”? Ответы на все эти вопросы лежат в основе ядра NodeJS - цикле событий (Event Loop). Это первая статья из серии где будет объяснено что такое Event Loop, как он работает и как это влияет на разработка.
Для начала, любой запрос ввода/вывода должен завершиться и вернуть ответ. Ответом будут запрошенные данные, если запрос успешно выполнился или ошибка, которая сообщит что запрос завершился неудачей. Получение этого ответа и называется событием. Эти события обрабатываются согласно следующему алгоритму:
- Event Demultiplexer получает запрос и отправляет его в соответствующую систему.
- после обработки ввода / вывода Event Demultiplexer регистрирует обработчики этого события, и, когда придет ответ, необходимый обработчик этого события будет добавлен в очередь событий (Event Queue)
- когда в очереди имеются события они обрабатываются в порядке их добавления в очередь
- если события больше нет и нет ожидающих ответа запросов, программа завершается
Именно это и есть Event Loop. Он однопоточный и почти бесконечный.
В целом это соответствует паттерну проектирования Reactor Pattern, но Event Loop более сложен, потому как Event demultiplexer это не один компонент, обрабатывающий все события ввода/вывода, да и очередь событий в нем не такая простая как может показаться.
Event Demultiplexer
В реальном мире не существует сущности Event Demultiplexer, это абстракция. В реальном мире он реализован во множестве разных систем, например epoll в Linux, kqueue в BSD системах (macOS), event ports в Solaris, IOCP (Input Output Completion Port) в Windows, и т.д.. NodeJS лишь предоставляет некоторую обертку для работы с ними. Для этого была разработана библиотека libuv, которая реализует большую часть этой абстракции
Event Queue
В NodeJS существует несколько очередей, и в каждую попадают события своего типа
После очередной главной очереди event loop обрабатывает события из двух промежуточных очередей.
Главные очереди, обрабатываемые libuv:
- очередь таймеров, пополняемая посредством функций setTimeout и setInterval
- события ввода/вывода
- очередь, пополняемая посредством функции setImmediate
- очередь обработчиков событий закрытия
Кроме 4 основных очередей существуют еще 2 очереди микрозадач (microtasks), прежде упомянутые как промежуточные, эти очереди уже являются частью NodeJS а не libuv:
- Next ticks queue - микрозадачи, добавленные посредством функции process.nextTick
- Microtasks queue - другие микрозадачи такие как колбеки завершенных промисов
После каждой фазы основного цикла выполняются эти внутренние очереди - сначала очередь next ticks, пока она не окажется пустой, а затем и очередь остальных микрозадач, пока и она не останется пустой.
Если во время выполнения очереди next ticks будут добавлены еще события в очередь next ticks, то они тоже будут выполнены до перехода к другим очередям, это может вызвать IO стагнацию - когда очередь событий наполняется быстрее чем обрабатывается и NodeJS просто не приступит к обработке других очередей событий
Перевод https://blog.insiderattack.net/event-loop-and-the-big-picture-nodejs-event-loop-part-1-1cb67a182810
Автор Arswarog
Обновлено 8 июня 2021