Цикл событий Node.js
Цикл событий — это основной механизм, с помощью которого Node.js обрабатывает неблокирующие операции ввода-вывода, позволяя одному потоку эффективно обрабатывать несколько одновременных запросов.
Node.js — это однопоточная среда выполнения JavaScript, которая использует цикл событий для обработки асинхронных операций, таких как чтение файлов, сетевые запросы и запросы к базе данных.
Цикл событий позволяет Node.js выполнять код неблокирующим образом, обрабатывать несколько соединений и выполнять асинхронные операции ввода-вывода.
Цикл событий позволяет Node.js обрабатывать большое количество одновременных операций ввода-вывода, не вызывая блокировки потоков; это ключ к эффективной обработке параллельных запросов в Node.js.

Фазы цикла событий
Цикл событий разделён на несколько фаз, каждая из которых обрабатывает определённые задачи. Ключевые фазы перечислены ниже:
- Таймеры: Выполнить
setTimeout()иsetInterval()обратные вызовы. - Обратные вызовы I/O: Обработка некоторых отложенных обратных вызовов ввода-вывода.
- Idle, prepare: Используется внутренне, встречается редко.
- Опрос: Получает новые I/O-события и выполняет связанные с I/O обратные вызовы.
- Проверка: Выполнить
setImmediate()обратные вызовы. - Обратные вызовы закрытия: Обрабатывает обратные вызовы закрытия, например
socket.on('close', ...)。
Поток цикла событий
- Задачи попадают в очередь цикла событий。
- Цикл событий обрабатывает в порядке фаз, и каждая фаза имеет свою собственную очередь обратных вызовов.
- Цикл событий будет в
pollфазе ожидания поступления новых событий; если событий нет, он проверит колбэки в других фазах. - Если
setImmediate()иsetTimeout()существуют оба,setImmediate()Вcheckфаза выполняется первой, в то время какsetTimeout()Вtimersфаза выполняется.
Пример
console.log('Timeout callback');
}, 0);
setImmediate(() => {
console.log('Immediate callback');
});
console.log('Main thread execution');
Порядок вывода:
Main thread executionВыводится первым.setImmediate()иsetTimeout()Порядок выполнения зависит от текущего состояния цикла событий; обычноsetImmediate()будет выполнен первым.
Макрозадачи и микрозадачи
- Макрозадачи:
setTimeout、setInterval、setImmediate, операции ввода-вывода и т. д. - Микрозадачи:
process.nextTick、Promise.then。
Порядок выполнения:Микрозадачи имеют более высокий приоритет, чем макрозадачи, и будут выполнены сразу после завершения колбэков текущей фазы.
Пример
console.log('Timeout callback');
}, 0);
Promise.resolve().then(() => {
console.log('Promise callback');
});
console.log('Main thread execution');
Результат вывода выполнения:
Main thread execution Promise callback Timeout callback
process.nextTick()
process.nextTick() выполняет микрозадачи после завершения текущей операции и до начала следующей фазы, с более высоким приоритетом, чем Promise.
Пример
console.log('Next tick callback');
});
console.log('Main thread execution');
Вывод:
Main thread execution Next tick callback
Событийно-ориентированная программа
В Node.js событийно-ориентированное программирование в основном реализуется через класс EventEmitter.
EventEmitter — это встроенный класс, находящийся в модуле events. Расширив EventEmitter, вы можете создать собственный эмиттер событий и регистрировать и запускать события.
Благодаря этому механизму Node.js может эффективно обрабатывать асинхронные задачи и обеспечивать конкурентную обработку даже в однопоточной среде.
Весь событийно-ориентированный поток реализуется именно так; это очень лаконично. Это несколько похоже на паттерн наблюдатель: событие эквивалентно субъекту (Subject), а все функции-обработчики, зарегистрированные на это событие, эквивалентны наблюдателям (Observer).
Основные понятия:
- Событие: действие или изменение состояния, происходящее в программе, например завершение чтения файла или поступление HTTP-запроса.
- EventEmitter:
EventEmitterявляется встроенным модулем Node.js, используемым для генерации и прослушивания событий. - Обработчик события: функция обратного вызова, связанная с событием, вызываемая при возникновении события.
Событийно-ориентированный поток:
- Регистрация события: В программе, через
EventEmitterэкземпляр регистрирует события и соответствующие обработчики. - Событие-триггер: Когда происходит указанное событие,
EventEmitterоно вызовет событие. - Обработка события: Цикл событий планирует выполнение соответствующей функции обратного вызова для выполнения задачи.
В Node.js есть множество встроенных событий. Мы можем привязывать и прослушивать события, импортируя модуль events и создавая экземпляр класса EventEmitter, как в следующем примере:
// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
Следующая программа привязывает обработчики событий:
// 绑定事件及事件的处理程序
eventEmitter.on('eventName', eventHandler);
Мы можем инициировать события с помощью программы:
// 触发事件
eventEmitter.emit('eventName');
Пример
Создайте файл hello.js, код выглядит следующим образом:
Пример 1
const myEmitter = new EventEmitter();
// Регистрация обработчика событий
myEmitter.on('greet', () => {
console.log('Hello, world!');
});
// Вызвать событие
myEmitter.emit('greet');
Вывод:
Hello, world!
Создайте файл main.js, код выглядит следующим образом:
Пример 2
Теперь давайте выполним приведённый выше код:
$ node main.js 连接成功。 数据接收成功。 程序执行完毕。
Как работает приложение Node?
В приложениях Node функции, выполняющие асинхронные операции, принимают функцию обратного вызова в качестве последнего параметра, а функция обратного вызова получает объект ошибки в качестве первого параметра.
Теперь давайте рассмотрим предыдущий пример. Создайте файл input.txt со следующим содержимым:
Example官网地址:www.example.com
Создайте файл main.js со следующим кодом:
var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
if (err){
console.log(err.stack);
return;
}
console.log(data.toString());
});
console.log("程序执行完毕");
В приведённой выше программе fs.readFile() — это асинхронная функция, используемая для чтения файлов. Если во время чтения файла возникает ошибка, объект ошибки err выведет сообщение об ошибке.
Если ошибка не возникает, readFile пропускает вывод объекта err, а содержимое файла выводится через функцию обратного вызова.
Выполните приведённый выше код, результат выполнения будет следующим:
程序执行完毕 Example官网地址:www.example.com
Теперь удалим файл input.txt, и результат выполнения будет следующим:
程序执行完毕 Error: ENOENT, open 'input.txt'
Поскольку файл input.txt не существует, выводится сообщение об ошибке.
Другие расширения