> Расскажите про асинхронность в JavaScript и средства работы с асинхронным кодом (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: amoCRM, циан, ООО Премиум ИТ Солюшен, Spotware, Домклик, EPAM, ООО Рокет Тех, Rutube, TYMY, Purrweb, ООО Снэп АйТи
Стек: JavaScript
> Пример ответа
Короткий ответ
Асинхронность в JavaScript - это способность выполнять операции без блокировки основного потока, основанная на event loop. Основные средства работы: callbacks, Promises и async/await. Event loop управляет очередями microtask и macrotask, обеспечивая неблокирующее выполнение. Для сложных сценариев используются комбинации Promise.all, Promise.race и обработка ошибок через try/catch.
Подробное объяснение
JavaScript является однопоточным языком с одним call stack и одним heap. Асинхронность реализуется через event loop, который координирует выполнение синхронного кода, microtask (Promise.then/catch/finally, queueMicrotask) и macrotask (setTimeout, setInterval, I/O).
Callbacks - исторически первый механизм, но приводят к callback hell. Promises (ES2015) предоставляют цепочки .then() и .catch() для композиции асинхронных операций. Async/await (ES2017) - синтаксический сахар над Promises, позволяющий писать асинхронный код в синхронном стиле.
Важные концепции: Promise.all для параллельного выполнения, Promise.race для первого завершённого, Promise.allSettled для всех результатов независимо от ошибок. Обработка ошибок в async/await через try/catch обязательна, так как необработанные rejection приводят к unhandledrejection.
На практике
Для параллельных запросов к API используйте Promise.all с обработкой ошибок через .catch на каждом запросе или общий try/catch. Для последовательных операций - async/await с циклом for...of, а не forEach, так как последний не поддерживает await корректно.
Избегайте создания Promise вручную (new Promise) без необходимости - используйте существующие асинхронные функции. Для таймаутов и retry-логики применяйте Promise.race с setTimeout. В Node.js для работы с потоками используйте streams или worker_threads, если требуется CPU-интенсивная работа.
Пример кода
JAVASCRIPT// Параллельная загрузка с обработкой ошибокasync function fetchUsers(ids) {const promises = ids.map(id =>fetch(`/api/users/${id}`).then(res => res.json()).catch(err => ({ id, error: err.message })));return Promise.all(promises);}// Последовательная обработка с таймаутомasync function processWithTimeout(items, timeout = 5000) {const results = [];for (const item of items) {const result = await Promise.race([processItem(item),new Promise((_, reject) =>setTimeout(() => reject(new Error('Timeout')), timeout))]);results.push(result);}return results;}
Как отвечать на собеседовании
Начните с event loop как фундамента, затем перечислите средства: callbacks, Promises, async/await. Объясните разницу между microtask и macrotask, приведите примеры. Покажите понимание Promise combinators (all, race, allSettled, any). Упомяните обработку ошибок и антипаттерны (например, забытый return в .then). Для senior уровня добавьте про memory leaks при неотменённых таймерах или подписках, про отличие между асинхронностью и параллелизмом.
Что проверяет интервьюер
- Понимание event loop и порядка выполнения (microtask vs macrotask)
- Умение выбирать правильный инструмент под задачу (callbacks, Promises, async/await)
- Знание Promise combinators и их особенностей
- Навыки обработки ошибок в асинхронном коде
- Понимание проблем (callback hell, unhandled rejection, race conditions)
- Способность объяснить, как работает await под капотом (генераторы + Promise)
Типичные ошибки
- Забывают, что forEach не ждёт await - нужно использовать for...of или Promise.all
- Не обрабатывают rejection в Promise.all - один reject убивает весь результат
- Создают Promise вручную, когда достаточно существующего API
- Путают параллельное и последовательное выполнение
- Не отменяют таймеры или подписки при размонтировании компонента
- Используют async/await без try/catch, полагаясь на глобальный обработчик
- Думают, что async/await делает код многопоточным
> Похожие задачи по frontend
Зачем нужен async/await в JavaScript
В чем разница function declaration, function expression и стрелочной функции в JavaScript
Как избежать ошибки при обращении к свойству объекта, если объект undefined?
Как работает callback в методе map в JavaScript и что означают его аргументы
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью