Цикл событий - один из наиболее важных аспектов работы Node.
- Вступление
- Блокировка цикла событий
- Стек вызовов
- Простое объяснение цикла событий
- Выполнение функции очереди
- Очередь сообщений
- Очередь заданий ES6
- Вывод
Вступление
ВЦикл событий- один из самых важных аспектов, которые нужно понять о Node.
Почему это так важно? Потому что он объясняет, как Node может быть асинхронным и иметь неблокирующий ввод-вывод, и поэтому в основном объясняет «убийственное приложение» Node, то, что сделало его таким успешным.
Код JavaScript для Node.js выполняется в одном потоке. Одновременно происходит только одно событие.
Это ограничение, которое на самом деле очень полезно, поскольку оно значительно упрощает программирование, не беспокоясь о проблемах параллелизма.
Вам просто нужно обратить внимание на то, как вы пишете свой код, и избегать всего, что может заблокировать поток, например, синхронных сетевых вызовов или бесконечныхпетли.
Как правило, в большинстве браузеров существует цикл событий для каждой вкладки браузера, чтобы изолировать каждый процесс и избежать веб-страницы с бесконечными циклами или тяжелой обработкой, чтобы заблокировать весь ваш браузер.
Среда управляет несколькими параллельными циклами событий, например, для обработки вызовов API.Веб-воркерытакже запускаются в собственном цикле событий.
В основном вам нужно беспокоиться о том, чтоваш кодбудет запускаться в одном цикле событий и писать код с учетом этого, чтобы избежать его блокировки.
Блокировка цикла событий
Любой код JavaScript, которому требуется слишком много времени для возврата управления в цикл обработки событий, будет блокировать выполнение любого кода JavaScript на странице, даже блокировать поток пользовательского интерфейса, и пользователь не может щелкать мышью, прокручивать страницу и т. Д.
Почти все примитивы ввода-вывода в JavaScript неблокирующие. Сетевые запросы, операции с файловой системой и т. Д. Блокировка - это исключение, и именно поэтому JavaScript так сильно основан на обратных вызовах, а в последнее время наобещанияиасинхронный / ожидание.
Стек вызовов
Стек вызовов представляет собой очередь LIFO (Last In, First Out).
Цикл событий постоянно проверяетстек вызововчтобы узнать, нужно ли запускать какую-либо функцию.
При этом он добавляет любой найденный вызов функции в стек вызовов и выполняет каждый из них по порядку.
Вы знаете трассировку стека ошибок, с которой вы, возможно, знакомы, в отладчике или в консоли браузера? Браузер просматривает имена функций в стеке вызовов, чтобы сообщить вам, какая функция инициирует текущий вызов:
Простое объяснение цикла событий
Возьмем пример:
я использую
foo
,bar
иbaz
в качествеслучайные имена. Введите любое имя, чтобы заменить их.
const bar = () => console.log('bar')
const baz = () => console.log(‘baz’)
const foo = () => {
console.log(‘foo’)
bar()
baz()
}
foo()
Этот код печатает
foo
bar
baz
как и ожидалось.
Когда этот код запускается, сначалаfoo()
называется. Внутриfoo()
мы сначала звонимbar()
, затем мы звонимbaz()
.
На данный момент стек вызовов выглядит так:
Цикл событий на каждой итерации проверяет, есть ли что-то в стеке вызовов, и выполняет это:
пока стек вызовов не станет пустым.
Выполнение функции очереди
Приведенный выше пример выглядит нормально, в нем нет ничего особенного: JavaScript находит вещи для выполнения, запускает их по порядку.
Давайте посмотрим, как отложить выполнение функции до тех пор, пока стек не очистится.
Вариант использованияsetTimeout(() => {}), 0)
заключается в том, чтобы вызвать функцию, но выполнить ее после того, как выполнятся все остальные функции в коде.
Возьмем этот пример:
const bar = () => console.log('bar')
const baz = () => console.log(‘baz’)
const foo = () => {
console.log(‘foo’)
setTimeout(bar, 0)
baz()
}
foo()
Этот код печатает, может быть, неожиданно:
foo
baz
bar
Когда этот код запускается, сначала вызывается foo (). Внутри foo () мы сначала вызываем setTimeout, передаваяbar
в качестве аргумента, и мы инструктируем его немедленно запускаться как можно быстрее, передавая 0 в качестве таймера. Затем мы вызываем baz ().
На данный момент стек вызовов выглядит так:
Вот порядок выполнения всех функций в нашей программе:
Почему это происходит?
Очередь сообщений
Когда вызывается setTimeout (), браузер или Node.js запускаюттаймер. По истечении таймера, в данном случае сразу после того, как мы установили 0 в качестве тайм-аута, функция обратного вызова помещается вОчередь сообщений.
В очереди сообщений также находятся инициированные пользователем события, такие как события щелчка или клавиатуры, илипринестиответы ставятся в очередь до того, как ваш код сможет на них отреагировать. Или такжеДОМтакие события, какonLoad
.
Цикл отдает приоритет стеку вызовов, и сначала он обрабатывает все, что находит в стеке вызовов, а когда там ничего нет, он переходит к подбору вещей из очереди сообщений.
Нам не нужно ждать таких функций, какsetTimeout
, fetch или другие вещи для выполнения своей работы, потому что они предоставляются браузером и живут в своих собственных потоках. Например, если вы установитеsetTimeout
тайм-аут до 2 секунд, вам не нужно ждать 2 секунды - ожидание происходит в другом месте.
Очередь заданий ES6
ECMAScript 2015представила концепцию очереди заданий, которая используется Promises (также представленная в ES6 / ES2015). Это способ как можно скорее выполнить результат асинхронной функции, а не помещать его в конец стека вызовов.
Обещания, которые выполняются до завершения текущей функции, будут выполнены сразу после текущей функции.
Мне нравится аналогия с поездкой на американских горках в парке развлечений: очередь сообщений помещает вас в конец очереди, позади всех остальных людей, где вам придется ждать своей очереди, а очередь заданий - это билет Fastpass что позволяет вам совершить еще одну поездку сразу после того, как вы закончили предыдущую.
Пример:
const bar = () => console.log('bar')
const baz = () => console.log(‘baz’)
const foo = () => {
console.log(‘foo’)
setTimeout(bar, 0)
new Promise((resolve, reject) =>
resolve(‘should be right after baz, before bar’)
).then(resolve => console.log(resolve))
baz()
}
foo()
Это печатает
foo
baz
should be right after baz, before bar
bar
В этом большая разница между Promises (и Async / await, который построен на обещаниях) и простыми старыми асинхронными функциями черезsetTimeout()
или API других платформ.
Вывод
Эта статья познакомила вас с основными строительными блоками цикла событий Node.js.
Это важная часть любой программы, написанной на Node.js, и я надеюсь, что некоторые из описанных здесь концепций будут полезны вам в будущем.
Скачать мою бесплатнуюСправочник по Node.js
Дополнительные руководства по узлам:
- Введение в менеджер пакетов npm
- Введение в Node.js
- HTTP-запросы с использованием Axios
- Где разместить приложение Node.js
- Взаимодействовать с Google Analytics API с помощью Node.js
- Средство выполнения пакетов npx Node
- Руководство по package.json
- Где npm устанавливает пакеты?
- Как обновить Node.js
- Как использовать или выполнить пакет, установленный с помощью npm
- Файл package-lock.json
- Семантическое управление версиями с использованием npm
- Следует ли зафиксировать папку node_modules в Git?
- Обновите все зависимости Node до последней версии
- Разбор JSON с помощью Node.js
- Найдите установленную версию пакета npm
- Node.js потоки
- Установите старую версию пакета npm
- Получить текущую папку в Node
- Как зарегистрировать объект в Node
- Предоставление функциональности из файла узла с помощью экспорта
- Различия между узлом и браузером
- Сделайте HTTP-запрос POST с помощью Node
- Получить данные тела HTTP-запроса с помощью Node
- Буферы узлов
- Краткая история Node.js
- Как установить Node.js
- Сколько JavaScript вам нужно знать, чтобы использовать Node?
- Как использовать Node.js REPL
- Узел, принимать аргументы из командной строки
- Вывод в командную строку с помощью Node
- Принять ввод из командной строки в Node
- Удаление пакетов npm с помощью `npm uninstall`
- npm глобальные или локальные пакеты
- зависимости npm и devDependencies
- Цикл событий Node.js
- Понимание process.nextTick ()
- Понимание setImmediate ()
- Эмиттер событий узла
- Создайте HTTP-сервер
- Выполнение HTTP-запросов с помощью Node
- Модуль Node fs
- HTTP-запросы в Node с использованием Axios
- Чтение файлов с помощью Node
- Пути к файлам узлов
- Написание файлов с помощью Node
- Статистика файла узла
- Работа с файловыми дескрипторами в Node
- Работа с папками в Node
- Модуль пути к узлу
- Модуль Node http
- Использование WebSockets с Node.js
- Основы работы с MySQL и Node
- Обработка ошибок в Node.js
- Путеводитель по мопсу
- Как читать переменные среды из Node.js
- Как выйти из программы Node.js
- Модуль Node os
- Модуль событий узла
- Узел, разница между разработкой и производством
- Как проверить, существует ли файл в Node.js
- Как создать пустой файл в Node.js
- Как удалить файл с помощью Node.js
- Как получить дату последнего обновления файла с помощью Node.js
- Как определить, сегодня ли дата в JavaScript
- Как записать объект JSON в файл в Node.js
- Почему вам следует использовать Node.js в вашем следующем проекте?
- Запускайте веб-сервер из любой папки
- Как использовать MongoDB с Node.js
- Используйте Chrome DevTools для отладки приложения Node.js
- Что такое pnpm?
- Список параметров среды выполнения Node.js v8
- Как исправить ошибку «Отсутствует доступ для записи» при использовании npm
- Как включить модули ES в Node.js
- Как создать дочерний процесс с помощью Node.js
- Как получить в Express и разобранное, и необработанное тело
- Как обрабатывать загрузку файлов в Node.js
- Каковы одноранговые зависимости в модуле Node?
- Как написать файл CSV с помощью Node.js
- Как читать CSV-файл с помощью Node.js
- Модули ядра узла
- Увеличение номеров сразу нескольких папок с помощью Node.js
- Как распечатать холст по URL-адресу данных
- Как создать и сохранить изображение с помощью Node.js и Canvas
- Как скачать изображение с помощью Node.js
- Как массово переименовывать файлы в Node.js
- Как получить имена всех файлов в папке в Node
- Как использовать обещания и ожидания с функциями обратного вызова Node.js
- Как протестировать пакет npm локально
- Как проверить текущую версию Node.js во время выполнения
- Как использовать Sequelize для взаимодействия с PostgreSQL
- Обслуживайте HTML-страницу с помощью Node.js
- Как устранить ошибку `util.pump is not a function` в Node.js