Share This
Связаться со мной
Крути в низ
Categories
//Как писать эффективный код на JavaScript с помощью Event Loop

Как писать эффективный код на JavaScript с помощью Event Loop

Event Loop (цикл событий) — один из важнейших аспектов в JavaScript, знание которого позволяет писать более эффективный код. В статье мы рассмотрим, как работает основной поток в JavaScript и как он обрабатывает асинхронные функции.

kak pisat effektivnyj kod na javascript s pomoshhju event loop 3f39ab4 - Как писать эффективный код на JavaScript с помощью Event Loop

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

Весь код в JavaScript выполняется в одном потоке, т. е. за один раз может обрабатываться только что-то одно. С одной стороны, это полезное ограничение, так как оно позволяет нам не задумываться об особенностях работы с параллелизмом. С другой стороны, мы постоянно должны контролировать код и заботиться о том, чтобы синхронные операции (бесконечные циклы, запрос данных по сети) не блокировали наш поток.

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

Undefined Meetup #6

23 сентября в 19:00, Онлайн, Беcплатно

tproger.ru События и курсы на tproger.ru

По факту окружение может одновременно управлять большим количеством «циклов событий» для обработки API-запросов. WebWorkers также имеют свой цикл событий.

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

Блокирование Event Loop

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

Почти все операции ввода/вывода в JavaScript являются неблокирующими — сетевые запросы, операции с файловой системой в Node.js и т. д. Исключением являются блокирующие операции, и именно поэтому в JavaScript так популярны обратные вызовы (callbacks), а в последнее время всё чаще начинают использовать Promise и async/await.

Разбираемся с Async/Await в JavaScript на примерахtproger.ru

Стек вызовов

Стек вызовов — это очередь LIFO (Last In, First Out).

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

Если вы знакомы со стеком вызовов в отладчике или консоли браузера, то пример далее будет вам понятен. Браузер ищет имена функций в стеке вызовов, чтобы сообщить вам, какая функция инициирует текущий вызов:

kak pisat effektivnyj kod na javascript s pomoshhju event loop cfbc302 - Как писать эффективный код на JavaScript с помощью Event Loop

Примеры работы с Event Loop

На небольшом примере мы рассмотрим, как работает Event Loop:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 757b764 - Как писать эффективный код на JavaScript с помощью Event Loop

Имена функций bar, baz, foo взяты в качестве примера.

После выполнения этот код выведет:

kak pisat effektivnyj kod na javascript s pomoshhju event loop e9536a2 - Как писать эффективный код на JavaScript с помощью Event Loop

В принципе, как и ожидалось.

Давайте подробно разберём, как этот код обрабатывается через Event Loop. Когда код выполняется, первым вызывается foo(), внутри foo() первой вызывается bar(), а затем baz().

В этот момент стек вызовов выглядит так:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 6abec8b - Как писать эффективный код на JavaScript с помощью Event Loop

Цикл обработки событий на каждой итерации проверяет, есть ли в стеке вызовы, и если да, выполняет их:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 106ec69 - Как писать эффективный код на JavaScript с помощью Event Loop

Этот процесс продолжается до тех пор, пока стек не станет пустым.

Порядок выполнения функций

В примере выше нет ничего специфичного: JavaScript анализирует код и определяет порядок вызова функций.

Давайте посмотрим, как мы можем изменить порядок вызова функций, сделав так, что определённая функция будет вызвана последней. Для этого мы выполним вызов нашей функции посредством browser API:

setTimeout(() => {}, 0);

Рассмотрим следующий пример:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 8c18789 - Как писать эффективный код на JavaScript с помощью Event Loop

Результат выполнения этого кода для некоторых может стать неожиданным:

kak pisat effektivnyj kod na javascript s pomoshhju event loop e6e51fa - Как писать эффективный код на JavaScript с помощью Event Loop

Когда этот код выполняется, сначала вызывается foo(). Внутри foo() мы сначала вызываем setTimeout, передавая bar в качестве аргумента, а временным интервалом указываем 0, чтобы вызов произошёл настолько быстро, насколько это возможно. Затем мы вызываем baz().

На этом этапе стек вызовов выглядит следующим образом:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 57470e2 - Как писать эффективный код на JavaScript с помощью Event Loop

Порядок вызова функций в этом случае будет выглядеть так:

kak pisat effektivnyj kod na javascript s pomoshhju event loop aa2ef8a - Как писать эффективный код на JavaScript с помощью Event Loop

Далее мы рассмотрим, почему так происходит.

Очередь сообщений (The Message Queue)

Когда вызывается setTimeout, браузер или Node.js запускают таймер. Когда время таймера истекает (в нашем случае это произойдёт немедленно, так как мы указали 0 в качестве временного интервала), наша callback-функция будет помещена в очередь сообщений.

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

В первую очередь Event Loop обрабатывает всё, что содержится в стеке вызовов, и только после этого начинает обрабатывать содержимое очереди.

Нам не нужно ждать, пока такие функции, как setTimeout, fetch или другие выполняют свою работу, поскольку они предоставляются браузером и живут в своих потоках. Например, если вы установите время ожидания setTimeout равным 2 секундам, вам не придётся ждать 2 секунды — ожидание происходит в отдельном потоке.

Очередь заданий (ES6 Job Queue)

ECMAScript 2015 представил концепцию очереди заданий, которая используется в Promises (также представлена в ES6/ES2015). Это способ выполнить результат асинхронной функции как можно скорее, а не помещать его в конец стека вызовов. Обещания, которые разрешаются до завершения текущей функции, будут выполняться сразу после текущей функции.

Это своего рода VIP-очередь, обработка которой имеет приоритет по отношению к обычной очереди.

Пример:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 628f0d1 - Как писать эффективный код на JavaScript с помощью Event Loop

Результат:

kak pisat effektivnyj kod na javascript s pomoshhju event loop 1fe4cec - Как писать эффективный код на JavaScript с помощью Event Loop

В этом большая разница между Promises (а также async/await, который построен на Promises) и привычными асинхронными функциями через setTimeout() или другие API-платформы.

Надеемся, статья поможет вам разобраться с работой Event Loop в JavaScript, включая работу с потоками, очередями событий и API браузера. Для наглядности мы рассмотрели несколько примеров и то, как их можно оптимизировать с точки зрения производительности.

Что нужно знать про массивы в JavaScripttproger.ru

Хинт для программистов: если зарегистрируетесь на соревнования Huawei Honor Cup, бесплатно получите доступ к онлайн-школе для участников. Можно прокачаться по разным навыкам и выиграть призы в самом соревновании.

Перейти к регистрации

  • 10 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close