Что подразумевается под циклом событий в JS?

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

JS среда выполнения состоит из кучи и стека. Ну, по крайней мере, это подтверждает движок V8 (среда выполнения JS в Chrome). Если это так, то как появляются такие вещи, как обратные вызовы? Как получилось, что вы можете использовать такие функции, как setTimeout, HttpRequests и т. д. Давайте посмотрим…

Это правда, что мы получаем только кучу и стек от таких двигателей, как V8. Мы получаем HttpRequests, DOM и setTimeout через то, что называется WebAPI. Так как же эти двое сосуществуют? Вот тут-то и появляется концепция цикла событий и очереди обратного вызова. Давайте углубимся в каждый из этих блоков один за другим.

Стек вызовов

Стек вызовов фиксирует состояние выполнения нашей JS-программы. Основной причиной использования стека вызовов является отслеживание точки, в которую каждая активная функция должна вернуть управление после завершения выполнения. Каждый вызов функции помещается в стек, и при каждом возврате функция извлекается из стека. JS имеет один стек вызовов, поскольку это однопоточный язык программирования.

Давайте используем простую программу JS ниже.

Вот как будет выглядеть стек вызовов для приведенной выше программы.

This — замечательный инструмент для визуализации стека вызовов для любой Js-программы.

Очередь задач/обратных вызовов и цикл событий

Давайте посмотрим на другой фрагмент кода.

Учитывая тот факт, что JS является однопоточным и может выполнять только одну задачу за раз, какой результат вы ожидаете от этой программы?

Измерьте приведенный выше пример с помощью практичной линзы. Что, если бы мы сделали HTTP-запрос, который может занять несколько минут, прежде чем мы получим ответ. Браузер останется заблокированным до этого времени и будет бесполезен. Не говоря уже о том, что это будет означать ужасный пользовательский опыт. С помощью веб-API, функций обратного вызова и цикла событий мы можем решить эту проблему.

Попробуйте запустить пример выше. Давайте посмотрим, почему мы получили то, что получили.
setTimeout — это API, предоставляемый браузером. Он принимает 2 аргумента, а именно функцию обратного вызова и время в миллисекундах, которое означает время, по истечении которого будет оцениваться функция обратного вызова. Когда setTimeout попадает в стек вызовов (после первого журнала консоли), он передается для обработки webApi и извлекается из стека (браузер отслеживает таймер, переданный функции setTimeout). Тем временем третий консольный оператор попадает в стек и выполняется. Как только webapi выполнен, он помещает функцию обратного вызова в «очередь задач/обратных вызовов». Здесь срабатывает цикл событий.

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

Замените 5000 на 0 в приведенном выше примере и посмотрите результат. Это доказывает, что «0» не означает «запустить немедленно». Это означает отсрочку выполнения этого блока кода до тех пор, пока стек не станет чистым, поскольку цикл событий может поместить элемент в стек, если стек пуст.

Ресурсы:

  1. Видеоурок от Филипа Робертса | JSConf ЕС
  2. Инструмент визуализации во время выполнения