Вопрос проверяет понимание асинхронного выполнения кода в JavaScript, в частности, как оператор await приостанавливает выполнение функции до разрешения Promise, не блокируя основной поток благодаря event loop.
Ключевое слово await используется внутри функций, объявленных с async. Его основная задача — заставить интерпретатор JavaScript "ждать" разрешения Promise, но делать это неблокирующим образом.
Когда движок встречает await somePromise, он немедленно приостанавливает выполнение текущей асинхронной функции. Функция возвращает управление тому, кто её вызвал (обычно это более высокий уровень кода или сам event loop). Код после await не выполняется до тех пор, пока Promise не перейдёт в состояние fulfilled (успех) или rejected (ошибка).
Event Loop — это механизм, который управляет выполнением кода, обрабатывая очередь задач (task queue) и очередь микрозадач (microtask queue). Когда выполнение асинхронной функции приостанавливается на await, движок помещает микрозадачу (microtask) в очередь микрозадач. Эта микрозадача содержит код, который должен возобновиться после разрешения Promise.
await, разрешается, соответствующая микрозадача извлекается из очереди и выполняется, возобновляя приостановленную функцию с результатом Promise.Рассмотрим простой пример с задержкой и запросом данных.
async function fetchData() {
console.log('Начинаем запрос...');
// Имитируем асинхронный запрос с задержкой
const data = await new Promise(resolve => {
setTimeout(() => resolve('Данные получены'), 1000);
});
console.log(data); // Выполнится после разрешения Promise
return data;
}
console.log('До вызова функции');
fetchData();
console.log('После вызова функции');
// Вывод в консоли:
// До вызова функции
// Начинаем запрос...
// После вызова функции
// (через 1 секунду) Данные полученыВ этом примере, когда выполнение доходит до await, функция fetchData приостанавливается, и управление возвращается, позволяя выполниться console.log('После вызова функции'). Через секунду Promise разрешается, микрозадача для возобновления fetchData попадает в очередь, и когда Call Stack пуст, Event Loop выполняет её, выводя "Данные получены".
Если Promise, переданный в await, отклоняется (rejects), это приводит к выбросу исключения в точке await. Это исключение можно перехватить с помощью try...catch внутри асинхронной функции.
async function riskyOperation() {
try {
const result = await Promise.reject('Что-то пошло не так!');
} catch (error) {
console.error('Ошибка перехвачена:', error);
}
}Итог: Оператор await — это синтаксический сахар для работы с Promise, который делает асинхронный код более линейным и читаемым. Его стоит применять везде, где нужно последовательно выполнять асинхронные операции, не блокируя при этом основной поток, например, при работе с API, чтении файлов или выполнении любых других I/O-задач.