Browser Event Loop

Модель конкуррентности в JS называется Event Loop и отличается от моделей конкурретности в таких языках как С++ и Java.

JS имеет однопточный рантайм, выполняющий одну вещь за раз. Каждая вкладка в браузере выполняется в отдельном процессе своим циклом событий (event loop - EL).

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

  • Разбор HTML

  • Выполнение JS кода в script тегах

  • Обработка реакций на действия пользователя (движения мыши, щелчки кнопок)

  • Обработка результатов (асинхронных) сетевых запросов.

Схематически, JS имеет следующий рантайм:

  • Выполнение функций формирует стек вызова.

  • Куча используется для хранения объектов (большой, неструктурированный регион памяти)

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

Очередь событий извлекает по одной задаче и выполняет её. EL использует последовательную (run-to-completion) семантику: текущая выполняемая задача всегда завершается полностью до того как следующая задача начнет выполняться. Таким образом, каждая задача имеет полный контроль над текущим состоянием программы и программисту нет волноваться по поводу конкуррентных модификаций. По завершению текущей задачи, из очереди событий извлекается следующая и передается на исполнение в JS-Runtime.

Параллельно с EL выполняется множество других фоновых процессов (таймеры, обработка ввода), которые взаимодействуют с EL помещая в его очередь задач новые задачи на выполнение. Эти фоновые процессы запускаются как самим браузером, так и из текущего пользовательского кода. Например, выполнение запроса из JS-кода создает фоновую задачу, выполняюуюся в WebApi браузера. По завершению выполнения запроса WebApi помещает задачу обработки запроса в EL.

Все задачи, связанные с JS (script и сетевые запросы) выполняются внутри встроенного в браузер JS-движка. Js-задачи завершаются вместе с завершением выполнения соответствующего им кода. JS-движок обеспечивает выполнение JS-кода, хранит стек вызовов, управляет кучей и т.п.

A web worker or a cross-origin iframe has its own stack, heap, and message queue. Two distinct runtimes can only communicate through sending messages via the postMessage method. This method adds a message to the other runtime if the latter listens to message events.

Asynchronous Primitives

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

Избежать блокирования позволяют различные методы асинхронного программирования и библиотеки:

  • Worker API - позволяет вынести длительные вычисления в отдельный параллельный процесс.

  • Asynchronous result - выполняя задачу, программист оставляет callback или другую функцию нотификации, которая будет вызвана когда задача завершится. Например, setTimeout это асинхронный sleep.

Существует два основных способа уведомления об асинхронном завершении задачи:

  • Events - для каждой задачи создается специальный объект, на котором регистрируются обработчики событий: один для успешного выполнения, другой для неудачного.

  • Callbacks - это функции, которые передаются для вызова в том случае, когда выполнение асинхронной операции завершилось. Недостаком Callback-ов являются более сложные сигнатуры функций, более сложная обработка ошибок и усложненная композиция функций.

Стиль программирования с использованием callback-ов часто называют CPS (continuation-passing style), поскольку следуший шаг выполнения явно передается в качестве параметра. Пример CPS:

Читать и понимать такой стиль на деле намного сложнее, чем последовательное выполнение. Для упрощения работы с асинхронными функциями в ES6 можно использовать новый инструментарий:

  • Promise

  • Generators

  • Сопутствующие библиотеки

Таймеры

JS имеет таймеры вида: setTimeout(callback, ms). Функция setTimeout ожидает заданное число ms а затем добавлет задачу по вычислению callback в очередь. Стоит отметить, что ms регулирует значение когда задача именно добавляется в EL, а не выполняется в нем.

requestAnimationFrame Функция requestAnimationFrame позволяет координировать перерисовки в браузере.

Last updated

Was this helpful?