> For the complete documentation index, see [llms.txt](https://imangazaliev.gitbook.io/reference/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://imangazaliev.gitbook.io/reference/js/async.md).

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

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` в цепочки

Подробнее:

* [Промисы](/reference/js/async/promises.md)
* [async/await](/reference/js/async/async-await.md)

## Событийный цикл (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**.

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

## Воркеры

[Воркеры](/reference/js/async/workers.md)

## Источники

* <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/>
