Node.js | Цикл событий
Node.js - это однопоточная платформа, управляемая событиями, которая может выполнять неблокирующее асинхронное программирование. Эти функции Node.js делают его более эффективным с точки зрения памяти. Цикл событий позволяет Node.js выполнять неблокирующие операции ввода-вывода, несмотря на то, что JavaScript является однопоточным. Это делается путем назначения операций операционной системе всякий раз, когда и где это возможно.
Большинство операционных систем являются многопоточными и, следовательно, могут обрабатывать несколько операций, выполняемых в фоновом режиме. Когда одна из этих операций завершена, ядро сообщает Node.js, и соответствующий обратный вызов, назначенный этой операции, добавляется в очередь событий, которая в конечном итоге будет выполнена. Это будет подробно объяснено позже в этом разделе.
Особенности цикла событий:
- Цикл событий - это бесконечный цикл, который ожидает задачи, выполняет их, а затем засыпает, пока не получит новые задачи.
- Цикл событий выполняет задачи из очереди событий только тогда, когда стек вызовов пуст, т.е. нет текущей задачи.
- Цикл событий позволяет нам использовать обратные вызовы и обещания.
- Цикл событий выполняет задачи, начиная с самых старых.
Пример:
console.log( "This is the first statement" ); setTimeout( function (){ console.log( "This is the second statement" ); }, 1000); console.log( "This is the third statement" ); |
Выход:
Это первое заявление Это третье утверждение Это второе утверждение
Объяснение: В приведенном выше примере первый оператор журнала консоли помещается в стек вызовов, и «Это первый оператор» регистрируется на консоли, и задача извлекается из стека. Затем setTimeout помещается в очередь, и задача отправляется в операционную систему, и для задачи устанавливается таймер. Затем эта задача извлекается из стека. Затем третий оператор журнала консоли помещается в стек вызовов, и «Это третий оператор» регистрируется в консоли, и задача извлекается из стека.
Когда таймер, установленный функцией setTimeout (в данном случае 1000 мс), истекает, обратный вызов отправляется в очередь событий. Цикл событий при обнаружении пустого стека вызовов берет задачу наверху очереди событий и отправляет ее в стек вызовов. Функция обратного вызова для функции setTimeout запускает инструкцию, и «Это вторая инструкция» регистрируется на консоли, и задача извлекается из стека.
Note: In the above case, if the timeout was set to 0ms then also the statements will be displayed in the same order. This is because although the callback with be immediately sent to the event queue, the event loop won’t send it to the call stack unless the call stack is empty i.e. until the provided input script comes to an end.
Работа цикла событий: когда запускается Node.js, он инициализирует цикл событий, обрабатывает предоставленный входной сценарий, который может выполнять асинхронные вызовы API, планировать таймеры, а затем начинает обработку цикла событий. В предыдущем примере сценарий начального ввода состоял из операторов console.log () и функции setTimeout (), которая планирует таймер.
При использовании Node.js для выполнения асинхронных операций используется специальный библиотечный модуль libuv. Эта библиотека также используется вместе с обратной логикой Node для управления специальным пулом потоков, который называется пулом потоков libuv. Этот пул потоков состоит из четырех потоков, используемых для делегирования операций, которые слишком тяжелы для цикла событий. Операции ввода-вывода, открытие и закрытие соединений, setTimeouts являются примерами таких операций.
Когда пул потоков завершает задачу, вызывается функция обратного вызова, которая обрабатывает ошибку (если есть) или выполняет другую операцию. Эта функция обратного вызова отправляется в очередь событий. Когда стек вызовов пуст, событие проходит через очередь событий и отправляет обратный вызов в стек вызовов.
Следующая диаграмма является правильным представлением цикла событий на сервере Node.js:
Фазы цикла событий: На следующей диаграмме показан упрощенный обзор порядка операций цикла событий:
- Таймеры: на этом этапе выполняются обратные вызовы, запланированные с помощью setTimeout () или setInterval ().
- Ожидающие обратные вызовы: здесь выполняются обратные вызовы ввода-вывода, отложенные до следующей итерации цикла.
- Idle, Prepare: используется только для внутреннего использования.
- Опрос: извлекает новые события ввода-вывода.
- Проверить: вызывает обратные вызовы setIntermediate ().
- Обратные вызовы закрытия: он обрабатывает некоторые обратные вызовы закрытия. Например: socket.on ('закрыть',…)