> For the complete documentation index, see [llms.txt](https://strctr.gitbook.io/programming/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://strctr.gitbook.io/programming/01-languages/javascript/05.-runtime-execution/browser-event-loop.md).

# Browser Event Loop

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

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

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

* Разбор HTML
* Выполнение JS кода в `script` тегах
* Обработка реакций на действия пользователя (движения мыши, щелчки кнопок)
* Обработка результатов (асинхронных) сетевых запросов.

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

![](/files/-MFL7fTP8C_i6yi0l2Os)

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

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

![](/files/-MFLAISWk2T7OgqJ44is)

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

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

![](/files/-MFLA8WrCBgPNvCDasuw)

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** - для каждой задачи создается специальный объект, на котором регистрируются обработчики событий: один для успешного выполнения, другой для неудачного.

```javascript
var req = new XMLHttpRequest();
req.open("GET", url);

req.onload = function() {
  if (req.status == 200) {
    processData(req.response);
  } else {
    console.log("ERROR", req.statusText);
  }
};

req.onerror = function() {
  console.log("Network Error");
};

req.send(); // Add request to task queue
```

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

```javascript
fs.readFile("myfile.txt", { encoding: "utf8" }, function(error, text) {
  // (A)
  if (error) {
    // ...
  }
  console.log(text);
});
```

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

```javascript
console.log("A");
identity("B", function step2(result2) {
  console.log(result2);
  identity("C", function step3(result3) {
    console.log(result3);
  });
  console.log("D");
});
console.log("E");

// Output: A E B D C

function identity(input, callback) {
  setTimeout(function() {
    callback(input);
  }, 0);
}
```

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

* `Promise`
* `Generators`
* Сопутствующие библиотеки

**Таймеры**&#x20;

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

```javascript
setTimeout(function() {
  // (A)
  console.log("Second");
}, 0);
console.log("First"); // (B)

First;
Second;
```

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


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://strctr.gitbook.io/programming/01-languages/javascript/05.-runtime-execution/browser-event-loop.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
