Ты наконец-то поймешь асинхронность в JS
Привет, друзья! Сегодня мы поговорим о том, что такое асинхронность в JavaScript и как она работает. Это одна из тех вещей, которые кажутся сложными, но на самом деле довольно просты, как только разберешься.
Понятие асинхронности и синхронности
Синхронный код — это код, который выполняется последовательно, один за другим. Ничего сложного, просто пошаговое выполнение. Для примера, вот как может выглядеть синхронный код:
console.log('Шаг 1');
console.log('Шаг 2');
console.log('Шаг 3');
А асинхронный код может выполняться параллельно с другими задачами. Это как многозадачность в нашей повседневной жизни: вы можете делать несколько вещей одновременно. Вот пример асинхронного кода:
console.log('Шаг 1');
setTimeout(function() {
console.log('Шаг 2');
}, 2000);
console.log('Шаг 3');
Практический пример с setTimeout
В примере выше мы использовали setTimeout
, чтобы задержать выполнение определенной функции на две секунды. Заметьте, что функция в setTimeout
выполняется асинхронно, а остальной код продолжает выполняться без ожидания.
Конечно, введем более детальные примеры и разберем, какие методы являются микрозадачами, а какие макрозадачами.
Микрозадачи и макрозадачи
В JavaScript некоторые операции создают микрозадачи, а некоторые — макрозадачи. Давайте рассмотрим примеры.
Микрозадачи
Микрозадачи обычно связаны с операциями, связанными с промисами. Вот несколько примеров операций, создающих микрозадачи:
Разрешение или отклонение промиса с помощью методов
.then()
,.catch()
и.finally()
.Использование
async/await
в асинхронных функциях.
Давайте рассмотрим пример с использованием промисов:
console.log('Начало');
Promise.resolve()
.then(() => console.log('Это микрозадача'))
.then(() => console.log('Это еще одна микрозадача'));
console.log('Конец');
Этот код создает две микрозадачи с помощью методов .then()
. Заметьте, что они выполняются после основной задачи, несмотря на то, что они добавляются в очередь раньше.
Макрозадачи
Макрозадачи обычно связаны с более крупными операциями или событиями в JavaScript, такими как выполнение скриптов, обработка событий DOM или выполнение кода в таймауте. Вот несколько примеров операций, создающих макрозадачи:
Выполнение скрипта.
Обработка событий DOM.
Выполнение кода в таймауте с помощью
setTimeout()
илиsetInterval()
.
Рассмотрим пример с использованием setTimeout()
:
console.log('Начало');
setTimeout(() => {
console.log('Это макрозадача');
}, 0);
console.log('Конец');
Этот код создает макрозадачу с помощью функции setTimeout()
. Заметьте, что она добавляется в очередь после основной задачи и даже после микрозадач.
Что будет обработано первее?
В рамках итерации цикла сначала выполняется макрозадача, затем — очередь микрозадач. Пока есть задачи — цикл их выполняет, а когда их нет — ожидает новых задач.
Преимущества понимания микро и макрозадач
Понимание различия между микрозадачами и макрозадачами важно для эффективного управления асинхронным кодом в JavaScript. Это помогает предсказать порядок выполнения операций и избежать неожиданных результатов.
Как это работает: Event Loop
Как происходит выполнение этих задач? Здесь на сцену выходит Event Loop — он следит за стеком вызова и очередями задач, управляя порядком выполнения. Как ведущий дирижер, он гарантирует, что все работает как надо.
Преимущества асинхронности
Асинхронный код позволяет создавать более отзывчивые и эффективные веб-приложения, не замораживая интерфейс. Он позволяет выполнять задачи в фоновом режиме, не блокируя основной поток выполнения.
Асинхронные методы и их особенности
Теперь, когда мы понимаем основы асинхронного программирования, давайте рассмотрим некоторые ключевые асинхронные методы и их особенности.
Пример с использованием Promise
console.log('Начало');
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Выполнено!');
}, 2000);
});
promise.then((result) => {
console.log(result);
});
console.log('Конец');
В этом примере мы создаем Promise, который выполняется через две секунды. Затем мы используем метод .then()
, чтобы обработать результат выполнения Promise. Заметьте, что код после создания Promise не ждет его выполнения и продолжает работу.
Пример с использованием async/await
console.log('Начало');
async function myAsyncFunction() {
const result = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Выполнено!');
}, 2000);
});
console.log(result);
}
myAsyncFunction();
console.log('Конец');
Здесь мы определяем асинхронную функцию, которая ожидает выполнения Promise с помощью ключевого слова await
. Это позволяет нам писать код, который выглядит как синхронный, но на самом деле выполняется асинхронно.
Преимущества использования Promise и async/await
Читаемость кода: Promise и async/await делают асинхронный код более читаемым и понятным, особенно при выполнении сложных последовательностей операций.
Управление ошибками: Promise предоставляет удобный способ обработки ошибок с помощью метода
.catch()
, а async/await позволяет использовать блокtry/catch
для обработки ошибок.Избегание callback hell: Использование цепочек Promise или async/await позволяет избежать так называемой «callback hell» — ситуации, когда множество вложенных обратных вызовов делают код трудным для чтения и отладки.
callback hell во своей своей красе
Заключение
Надеюсь, что этот более глубокий обзор асинхронного программирования в JavaScript помог вам лучше понять, как использовать асинхронные методы, а также какие преимущества они предоставляют.
Поиграться с асинхронностью можно на этом сайте https://www.jsv9000.app/