# Асинхронность

JavaScript - синхронный, блокирующий и однопоточный язык.

* Однопоточность — JavaScript работает в однопоточном режиме, т.е. только одна операция может быть выполнена в определенный момент времени.
* Синхронное выполнение кода — код выполняется синхронно, т.е. следующая операция не выполняется до завершения предыдущей.

## Синхронный и асинхронный код

Синхронный код - когда команды выполняются одна за другой. Пока выполняется одна операция, другие ожидают ее завершения.

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

Примеры асинронных событий:

* События
* HTTP-запрос
* Таймеры (`setTimeout`/`setInterval`)
* Чтение/запись файла (Node.js)
* Обращение к базе (Node.js)

Все асинхронные функции, которые используются в JavaScript - это Web API, если речь идет о браузере, либо модули NodeJS, когда речь идет о бэкенде. Обращение к этим функциям запускает нативный код внутри Web API или Node.js (таймер, выполнение запроса, чтение и т. д.).

Есть **два стиля** написания асинхронного кода - это коллбэки и промисы.

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

Если требуется выполнить несколько асинхронных операций подряд, может возникнуть ситуация, когда приходится делать несколько уровней вложенности коллбэков. Большую вложенность коллбэков называют “**callback hell**”.

## Промисы, async/await

Плюсы промисов по сравнению с коллбэками:

* Позволяют избежать большой вложенности (callback hell), используя цепочку `then`
* Ошибки в цепочке асинхронных событий можно обработать одним блоком `catch` в цепочки

Подробнее:

* [Промисы](https://imangazaliev.gitbook.io/reference/js/async/promises)
* [async/await](https://imangazaliev.gitbook.io/reference/js/async/async-await)

## Событийный цикл (event loop)

После выполнения асинхронной функции, коллбэк, который был указан, добавляется **очередь задач** самим Web API или Node.js. Это может быть завершение таймера или какое-то событие:

* действие пользователя (клик, ввод, скролл),
* сообщение из воркера, iframe и т. д.
* ответ от сервера
* и т. д.

Дальше в дело вступает событийный цикл (**event loop**). Идея событийного цикла очень проста. Есть бесконечный цикл, в котором движок JavaScript ожидает задачи в очереди и добавляет их стек. Каждая задача в очереди - это какая-то функция (коллбэк)

Очередь представляет собой FIFO (fist in, first out), т. е. первая очередь в задаче будет выполнена раньше всех.

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

Наглядная демонстрация event loop: [http://latentflip.com/loupe/](http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D).

Задачи в очереди называют также **макротасками** или **макрозадачи**.

Между ними выполняются **микрозадачи** (**микротаски**). Они выполняются подряд, без прерываний, пока не будут выполнены все.

Откуда берутся микротаски?

* `Promise.then`
* Mutation observer
* `process.nextTick` (Node.js)

В процессе выполнения одной микротаски, можно создавать новые, которые будут выполнены в этом же промежутке, который называется **microtask checkpoint**.

Микрозадачи выполняются не только после выполнения макрозадач, но и после очистки стека.

## Воркеры

[Воркеры](https://imangazaliev.gitbook.io/reference/js/async/workers)

## Источники

* <https://developer.mozilla.org/ru/docs/Web/JavaScript/EventLoop>
* <https://learn.javascript.ru/event-loop>
* <https://habr.com/ru/post/439620/>
* <https://habr.com/ru/post/264993/>


---

# Agent Instructions: 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://imangazaliev.gitbook.io/reference/js/async.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.
