Цикл событий JavaScript: концепция

Для работы с JavaScript (другими словами, для разработки любого веб-сайта, а в последнее время и для серверной платформы node.js) необходимо понимать, как работает Цикл событий.

Цикл событий

Цикл событий, как следует из названия, представляет собой цикл, в котором события обрабатываются одно за другим. Обычно он принимает вид:

Цикл будет обрабатывать каждое событие по мере его поступления по принципу FIFO (First In First Out). Когда событие инициируется, оно добавляется в очередь цикла событий как сообщение, которое необходимо обработать, и оно должно ожидать своей очереди. Как только событие переместится в начало очереди, механизм JavaScript выполнит это событие. Как только событие начинает обрабатываться, оно не может быть вытеснено другим событием до его завершения. Эта функция называется Run-To-Completion и очень полезна программистам для понимания природы обработки JavaScript. В этот период не могут начинаться новые события, т. е. Javascript детерминирован.

Когда я говорю начало, я имею в виду, что новое событие не может начать обработку. Но ничто не мешает новому событию попасть в очередь. В конце концов, очередь предназначена для одного: ожидания!

Упомянутая выше очередь называется Очередь сообщений, и каждое инициированное событие создает новое сообщение и добавляет его в очередь для обработки. Основная функция цикла событий — обрабатывать сообщения (и соответствующее событие) в том порядке, в котором они были добавлены в очередь.

Скажем, вы вызываете 2 события одно за другим, и второму событию нужны данные, которые должны быть изменены/сгенерированы первым событием. Как веб-разработчик, вы ожидаете, что 2 события будут обрабатываться одно за другим. Что ж, тогда вы можете безопасно работать с JavaScript! Потому что в JavaScript встроена однопоточная обработка. Это называется «моделью параллелизма» движка JavaScript.

Пример

Приведенный выше код напечатает [1, 2]. Потому что функция внутри setTimeout() выполняется только после того, как текущая очередь событий пуста, то есть после выполнения последней строки console.log().

Примечание. Воспользуйтесь этим отличным инструментом, созданным Филипом Робертсом, чтобы лучше представить себе, как работает Event Loop! Повторно запустите пример кода и просто посмотрите, что произойдет. Это позволяет легко понять, как именно JavaScript обрабатывает события.

параллелизм

Модель параллелизма имеет интересный побочный эффект: поскольку события обрабатываются по порядку, функции обратного вызова никогда не будут вызываться до тех пор, пока вызывающая функция не завершит выполнение!

Обещания стали возможными благодаря этому аспекту языка JavaScript. И они сделали нашу жизнь проще, не так ли?!

Javascript является однопоточным и неблокирующим! Чувствуется противоречие, но это не так. Позволь мне объяснить.

Поскольку события обрабатываются в том же порядке, в котором они добавляются в очередь сообщений, можно ожидать, что операции IO будут блокировать дальнейшую обработку до их завершения. Но это не так. :) Любая операция IO выполняется путем отправки событий в соответствующие веб-API с прикрепленными к этим событиям функциями обратного вызова. Функции обратного вызова позволяют Javascript выполнять операции ввода-вывода неблокирующим образом.

Несмотря на то, что JavaScript является однопоточным синхронным языком с блокировкой, среда, в которой выполняется JavaScript, позволяет выполнять асинхронные вызовы функций. Выполняя операции ввода-вывода через такие API, JavaScript может обрабатывать несколько вещей, не блокируя основной поток.

Пример

Вот пример кода для кнопки Submit, используемой для отправки комментариев. Функция отправки использует вызов AJAX для отправки комментария на сервер с функциями обратного вызова для обработки успеха/ошибки (выполнено/неудачно).

Комментарий отправляется, и последний console.log() выполняется без задержки. Всякий раз, когда вызов запроса возвращается, он выполняет console.log внутри!

Это иллюстрирует неблокирующий характер JavaScript. Если пользователь взаимодействует с веб-сайтом во время вызова submit, веб-сайт может отреагировать на пользователя. В документах Mozilla даже говорится, что JavaScript никогда не блокируется.

Обещания ES6

Единственным исключением из концепции очереди сообщений является то, как (или, скорее, когда) разрешаются промисы. Вы ожидаете, что обещание, которое разрешается, будет добавлено в конец очереди для обработки. Но Promise предназначен для ожидания как можно меньшего времени перед выполнением!

Как вы гарантируете, что обещание будет выполнено в ближайшее время без ущерба для функции Run-To-Completion? Добавив его в начало очереди! Так что он будет выполнен, как только текущая функция завершится. Это гарантирует, что асинхронному вызову не придется слишком долго ждать после возврата, чтобы начать выполнение.

Я надеюсь, что эта статья пролила свет на цикл событий языка JavaScript и дала вам лучшее понимание модели параллелизма.

Если вы хотите глубже понять цикл событий, уже есть несколько доступных ресурсов. Те, которые я нашел полезными, приведены ниже:

Примечание. Фото на обложке сделано Pankj Patel на Unsplash!

Первоначально опубликовано на www.amithraravi.com 19 сентября 2019 г.