Асинхронность: callbacks, Promise, async/await
↑ 2.1 JavaScript: продвинутый · ← Предыдущая · → Следующая
Зачем это на собесе
Асинхронность — основа фронтенда. Ждут понимания состояний Promise, комбинаторов и обработки ошибок.
Объяснение
Callbacks приводят к «аду колбэков» и сложной обработке ошибок. Promise — объект будущего результата: pending → fulfilled | rejected (состояние необратимо).
const p = new Promise((resolve, reject) => setTimeout(() => resolve(42), 100));
p.then(v => v * 2).then(console.log).catch(console.error).finally(cleanup);
fetch("/api").then(r => r.json()); // цепочка: then возвращает новый Promise| Комбинатор | Результат |
|---|---|
Promise.all([...]) | все успешны (или первая ошибка) |
Promise.allSettled | результаты всех со статусами |
Promise.race | первый завершившийся |
Promise.any | первый успешный (или AggregateError) |
Promise.withResolvers() | внешние resolve/reject |
async/await — синтаксис над Promise:
async function load(ids, signal) {
try {
const [user, orders] = await Promise.all([api.user(ids.u, { signal }), api.orders(ids.u, { signal })]); // параллельно
for (const id of ids.items) await process(id); // последовательно
return { user, orders };
} catch (e) {
if (e.name === "AbortError") return null;
throw e;
}
}Правила:
async-функция всегда возвращает Promise;awaitприостанавливает функцию (не поток).awaitв цикле выполняет последовательно; для параллельности —Promise.all.- Ошибка в
async— отклонённый Promise;try/catchвокругawait. - Продолжение после
await— микрозадача (см. Event Loop: микро- и макрозадачи).
Нюансы и подводные камни
- Забытый
await— «плавающий» промис без обработки ошибок (unhandledrejection). forEach(async …)не ждёт завершения.Promise.allотклоняется при первой ошибке, остальные продолжают выполняться.- Отмена промисов невозможна: используйте
AbortControllerи передавайтеsignal. return awaitвнутриtryнужен для перехвата ошибки; внеtryизбыточен.
Практика
- Перепишите вложенные коллбэки на Promise, затем на async/await.
- Реализуйте
retry(fn, n)иtimeout(promise, ms). - Распараллельте три независимых запроса и обработайте частичные ошибки через
allSettled.
Вопросы с ответами
Чем
Promise.allотличается отallSettled?
allпадает при первой ошибке,allSettledждёт все и возвращает статусы каждого.
Что делает
await?Приостанавливает выполнение async-функции до завершения промиса; главный поток при этом свободен.
Как отменить запрос?
AbortController: передатьsignalвfetchи вызватьabort().