JavaScript был разработан как встроенный язык сценариев. Программы JavaScript не работают как отдельные приложения, а в качестве сценариев в контексте более крупного приложения. Флагманский пример, конечно же, веб -браузер. В браузере может быть много Windows и вкладок, работающих с несколькими веб -приложениями, каждая из которых отвечает на различные входы и стимулы: действия пользователя с помощью клавиатуры, мыши или прикосновения, прибытие данных из сети или временные тревоги. Эти события могут происходить в любой точке – даже одновременно – в случае срока службы веб -приложения. И для каждого вида события приложение может пожелать быть уведомленным о информации и ответить на пользовательское поведение. Подход JavaScript к написанию программ, которые реагируют на множественные параллельные события, удивительно удобен для пользователя и мощный, используя комбинацию простой модели выполнения, иногда известной как очередь событий или параллелизм событий, с тем, что известны как асинхронные API. Благодаря эффективности этого подхода, а также тому факту, что JavaScript стандартизирован независимо от веб-браузеров, JavaScript используется в качестве языка программирования для множества других приложений, от настольных приложений до серверных каркасов, таких как Node.js. Любопытно, что на сегодняшний день стандарт Ecmascript никогда не говорил ни слова о параллелизме. Следовательно, эта глава посвящена «фактическим» характеристикам JavaScript, а не официальным стандартом. Тем не менее, большинство среда JavaScript имеют один и тот же подход к параллелизму, и будущие версии стандарта могут стандартизировать эту широко реализованную модель выполнения. Независимо от стандарта, работа с событиями и асинхронными API является фундаментальной частью программирования в JavaScript.
Не блокируйте очередь событий в I/O 🥞 🥞
Программы JavaScript структурированы вокруг событий: входные данные, которые могут прийти одновременно из множества внешних источников, таких как взаимодействие от пользователя (нажимая кнопку мыши, нажатие На некоторых языках обычно писать код, который ждет конкретного ввода:
var text = downloadSync("http://example.com/file.txt");
console.log(text);
Console.Log API является распространенной утилитой на платформах JavaScript для печати отладки информации в консоли разработчика.
Функции, такие как Скачатьсинк известны как синхронные или блокирующие: Программа перестает выполнять любую работу, пока она ждет своего ввода в этом случае, результат загрузки файла через Интернет. Поскольку компьютер может выполнять другую полезную работу, пока он ожидает завершения загрузки, такие языки обычно предоставляют программисту способ создания нескольких потоков: подкомпутации, которые выполняются одновременно, позволяя одной части программы остановиться и ждать («блокировать») медленный вход, в то время как другая часть программы может продолжать использование самостоятельной работы.
В JavaScript большинство Операции ввода/вывода предоставляются через асинхронные или неблокирующие API. Вместо того, чтобы блокировать нить в результате , программист предоставляет обратный вызов (см. Пункт 19), чтобы система вызвала, когда вход придет:
downloadAsync("http://example.com/file.txt", function(text) {
console.log(text);
});
Вместо того, чтобы блокировать сеть, этот API инициирует процесс загрузки, а затем немедленно возвращается после хранения обратного вызова во внутреннем реестре. В какой -то момент, когда загрузка завершена, система вызывает зарегистрированный обратный вызов, передавая его текст загруженного файла в качестве аргумента. Теперь система не просто прыгает прямо и называется обратным вызовом, который завершается загрузка. JavaScript иногда описывается как предоставление гарантии заполнения на завершение: любой код пользователя, который в настоящее время работает в общем контексте, такой как одна веб-страница в браузере, или один управляющий экземпляр веб-сервера, разрешено завершить Выполнение перед следующим обработчиком событий. По сути, система поддерживает внутреннюю очередь событий по мере их возникновения, и вызывает любые зарегистрированные обратные вызовы по одному.
На изображении ниже показана иллюстрация примеров очередей событий в приложениях на стороне клиента и на стороне сервера. По мере того, как происходят события, они добавляются к окончанию очереди событий приложения (в верхней части диаграммы). Система JavaScript выполняет приложение с внутренним циклом события, который срывает события с нижней части очереди, то есть в том порядке, в котором они были получены, и вызывает любые зарегистрированные обработки событий сценария Java (обратные вызовы, такие как тот, который передал к Скачать Aasync выше) по одному, передавая данные события в качестве аргументов для обработчиков.
Пример очередей событий в а) приложении веб -клиента и б) веб -сервера.
Преимущество гарантии заполнения к завершению состоит в том, что когда ваш код запускается, вы знаете, что у вас есть полный контроль над состоянием приложения: вам никогда не придется беспокоиться о том, что какая-то переменная или свойство объекта изменится из-под вас из-за одновременного выполнения код. Это имеет приятный результат, что одновременное программирование в Java-Script, как правило, намного проще, чем работа с потоками и блокировками на таких языках, как C ++, Java или C#.
И наоборот, недостаток запуска к завершению заключается в том, что любой код, который вы пишете эффективно, удерживает оставшуюся часть приложения. В интерактивных приложениях, таких как браузер, заблокированный обработчик событий предотвращает обработку любого другого пользовательского ввода и может даже предотвратить рендеринг страницы, что приводит к небезопасному пользовательскому опыту. В настройке сервера заблокированный обработчик может предотвратить обработку других сетевых запросов, что приведет к невосприимчивому серверу.
Единственное наиболее важное правило одновременного JavaScript никогда не использует блокировку API ввода/вывода в середине очереди событий приложения. В браузере едва ли доступны блокирующие API, хотя некоторые из них, к сожалению, просочились на платформу на протяжении многих лет. Xmlhttprequest Библиотека, которая обеспечивает сетевой ввод -вывод, аналогичный Скачать Aasync Функция выше, имеет синхронную версию, которая считается плохой формой. Синхронный ввод -вывод имеет катастрофические последствия для интерактивности веб -приложения, что мешает пользователю взаимодействовать со страницей до завершения операции ввода -вывода.
В отличие от этого, асинхронные API безопасны для использования в на основе событий, потому что они заставляют вашу логику приложения продолжать обработку в отдельном «повороте» цикла событий. В примерах выше представьте, что для загрузки URL требуется пару секунд. За это время может произойти огромное количество других событий. В синхронной реализации эти события будут накапливаться в очереди событий, но цикл событий будет застрять в ожидании кода JavaScript, чтобы закончить выполнение, предотвращая обработку любых других событий. Но в асинхронной версии код JavaScript регистрирует обработчик событий и немедленно возвращается, позволяя другим обработчикам событий обрабатывать промежуточные события до завершения загрузки
В настройках, где очередь событий основного приложения не затронута, операции блокировки менее проблематичны. Например, веб -платформа предоставляет API работника, что позволяет создавать одновременные вычисления. В отличие от обычных потоков, работники выполняются в полностью изолированном состоянии, без доступа к глобальному объему или содержимому веб -странице основного потока приложения, поэтому они не могут мешать выполнению кода, работающего из основной очереди события. В рабочем, используя синхронный вариант Xmlhttprequest менее проблематично; Блокирование загрузки мешает продолжить работника, но это не препятствует рендеринге страницы или очередь событий отвечать на события. В настройке сервера блокировка API не является беспроблемной во время запуска, то есть до того, как сервер начнет реагировать на входящие запросы. Но Когда Запросы на обслуживание, блокировка API столь же катастрофична, как и в очереди браузера.
Вещи, чтобы помнить 🧠
- Асинхронные API предпринимают обратные вызовы, чтобы отложить обработку дорогих операций и избежать блокирования основного приложения.
- JavaScript принимает события одновременно, но обрабатывает обработчики событий последовательно, используя очередь событий.
- Никогда не используйте блокировку ввода -вывода в очереди событий приложения
Оригинал: “https://dev.to/jrmatanda/the-truth-about-event-loop-part-1-2l31”