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

Предпосылки:

Что ж, чтобы понять «Event Loop», вам просто нужно иметь базовое понимание языка JavaScript.

Плита котла:

  1. Однопоточный синхронный язык
  2. Блокирующие и неблокирующие заявления
  3. Веб-API браузера

Давайте погрузимся в это.

  1. Однопоточный синхронный язык

Как вы все знаете, JavaScript - это однопоточный синхронный язык. Что это значит?
Однопоточный: это означает, что JavaScript имеет только один стек вызовов и одну кучу памяти.
Синхронный: это означает, что JavaScript может запускать только один оператор за раз.

2. Блокирующий и неблокирующий код

Блокирующий код: следующий оператор не может быть выполнен до тех пор, пока текущий оператор не будет выполнен полностью.
Например,

Неблокирующий код: следующий оператор может быть выполнен, оставив текущий оператор в стороне на некоторое время.
Например,

Примечание. Внимательно ознакомьтесь с выводом примера неблокирующего кода.

Примечание. Если вы не поняли пример неблокирующего кода. Не волнуйтесь, мы подробно рассмотрим это позже.

3. Веб-API браузера

Браузер предоставляет механизму JavaScript некоторые веб-API для использования его функций, таких как таймер, местоположение, консоль и т. Д. Браузер объединяет все эти функции в единый глобальный объект «окно» и делает этот глобальный объект доступным для механизма JavaScript. Теперь, используя этот объект окна, движок JavaScript может получить доступ к функциям браузера.
Например,

Примечание. Поскольку объект окна является глобальным объектом и доступен для движка JavaScript, мы можем напрямую использовать console.log (), несмотря на window.console.log ().

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

Основная тема (Цикл событий):

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

Всякий раз, когда программа запускается, создается глобальный контекст выполнения, который перемещает его в верхнюю часть стека вызовов. И когда функция вызывается, создается контекст функции и помещается в стек вызовов. Как только он будет полностью выполнен, он будет извлечен из стека вызовов.

Глобальный контекст выполнения: это просто среда, в которой выполняется и оценивается код JavaScript.

Стек вызовов: используется для управления контекстами выполнения.

Например,

Давайте посмотрим, что произойдет, когда приведенный выше код будет выполнен.

Как я упоминал ранее, глобальный контекст выполнения будет создан для этой программы и помещен в верхнюю часть стека вызовов.

* GEC: глобальный контекст выполнения

Теперь выполняется первая строка. Поскольку это объявление функции, функция сохраняется в памяти. Когда выполнение программы достигает строки 5, вызывается printHello (). Следовательно, он будет помещен в стек вызовов.

Когда выполняется printHello (), в консоли будет напечатано «Hello», а когда он завершит свое выполнение, оно будет извлечено из стека вызовов.

Теперь выполнение переходит к строке 7, и в консоли будет напечатано «Пока».

Теперь же программа выполнена полностью. GEC извлекается из стека вызовов.

Так стек вызовов управляет контекстом выполнения.

Теперь мы лучше понимаем, как работает стек вызовов и как GEC выталкивается и извлекается из стека вызовов. Итак, это все. Не правда ли?

Но ждать….

Что, если через какое-то время потребуется выполнить какой-то код. Что тогда будет со стеком вызовов? Будет ли оставшийся код ждать выполнения предыдущего кода?

ЗАДЕЙСТВУЙТЕ ЗДЕСЬ и подумайте над ответами на эти вопросы.

Итак, давайте рассмотрим один пример того, как стек вызовов и GEC реагируют, когда через некоторое время необходимо выполнить некоторый код.

Давайте посмотрим, что произойдет, когда приведенный выше код будет выполнен.

Как я упоминал ранее, глобальный контекст выполнения будет создан для этой программы и помещен в верхнюю часть стека вызовов.

Теперь выполнение программы начинается со строки 1. И в консоли будет напечатано «Добро пожаловать в программу».

Теперь выполнение программы переходит к строке 3, где написана функция setTimeout (). Здесь произойдет интересное. Обратный вызов (printHello ()), записанный внутри setTimeout (), будет зарегистрирован в браузере, и выполнение программы переместится в строку 7. (Как я упоминал ранее, JavaScript - это синхронный однопоточный язык. Таким образом, он не будет ждать для любого кода, который будет выполнен через некоторое время). Что происходит с этим обратным вызовом setTimeout ()? Мы увидим это позже. По мере того, как выполнение программы переходит к строке 7, «Пока!» будет напечатан в консоли.

Тем временем мы выполняем наш код, таймер все еще работает в фоновом режиме. Как только таймер истечет, зарегистрированная функция обратного вызова должна быть помещена в стек вызовов и запущена. Но как с этим справиться?

Когда наша программа подошла к концу, GEC будет извлечен из стека вызовов.

Давайте посмотрим…

Как только таймер истекает, функция обратного вызова попадает в очередь обратного вызова. Вы должны задаться вопросом, что это за очередь обратного вызова?

Очередь обратного вызова: это обычная очередь, в которой все зарегистрированные функции обратного вызова ждут своего выполнения. Он работает по принципу FIFO (First In First Out). Он содержит такие задачи, как setTimeout, setInterval, I / O и т. Д.

Теперь мы переходим к нашей основной теме, то есть циклу событий. Цикл событий имеет только одно задание, то есть непрерывный мониторинг очереди обратного вызова и стека вызовов. Всякий раз, когда стек вызовов становится пустым, цикл событий подталкивает функции обратного вызова, ожидающие внутри очереди обратного вызова, в стек вызовов. Как только функции обратного вызова помещены в стек вызовов, начинается их выполнение.

В нашей программе через 2 секунды функция printHello () помещается в очередь обратного вызова. Цикл событий постоянно проверяет очередь обратных вызовов и стек вызовов. И теперь стек вызовов пуст, поэтому цикл событий подтолкнет функцию printHello (), присутствующую в очереди обратного вызова, в стек вызовов.

Функция printHello () начинает свое выполнение и выводит «Hello» в Консоль. По завершении выполнения функция printHello () будет извлечена из стека вызовов, и выполнение программы завершится.

Вот как работает цикл событий. Что ж, есть еще одна очередь под названием Microtask Queue.

Очередь микрозадач: это просто еще одна очередь, в которой такие задачи, как Promises, MutationObserver, queueMicrotask и т. Д., После разрешения находятся и ждут своего выполнения.

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

Вот и все. Надеюсь, вы получите полное представление о Event Loop и о том, как он работает. Вы шли со мной до этого места, тогда не забудьте показать большой палец вверх 👍, если вы сочли это полезным.