> В чем разница между async function и обычной функцией в JavaScript? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: EPAM

Стек: JavaScript

> Пример ответа

Короткий ответ

Основное различие в том, что async function всегда возвращает Promise, даже если явно возвращается не-promise значение. Внутри async function можно использовать await для приостановки выполнения до разрешения Promise. Обычная функция возвращает то, что указано в return, синхронно, и не поддерживает await без дополнительных обёрток.

Подробное объяснение

Async function - это синтаксический сахар над генераторами и промисами. Когда вызывается async function, она немедленно возвращает Promise, который разрешится значением, возвращённым из функции, или отклонится с ошибкой. Если внутри async function нет await, она всё равно вернёт Promise.resolve() от возвращаемого значения.

Обычная функция выполняется синхронно: её вызов блокирует поток до завершения, и возвращаемое значение доступно сразу. Для работы с асинхронными операциями в обычных функциях нужно явно использовать Promise.then() или callback.

Ключевые отличия:

  • Возвращаемое значение: async function всегда оборачивает результат в Promise, обычная - возвращает как есть.
  • Контекст выполнения: async function может приостанавливаться на await, освобождая event loop; обычная функция выполняется до конца без пауз.
  • Обработка ошибок: в async function можно использовать try/catch для await, в обычной - только .catch() на промисах.
  • Стек вызовов: при await текущий фрейм покидает стек, что влияет на трассировку и производительность.

На практике

Для senior-разработчика важно понимать, что async/await - это не магия, а работа с Promise под капотом. При использовании async function без await внутри она всё равно создаёт лишний микрозадачу, что может быть неоптимально для горячих путей. Также стоит помнить, что async function нельзя использовать как конструктор с new, и она не имеет доступа к arguments в строгом смысле (но можно через rest parameters).

Типичный сценарий: async function для обработки запросов к API, обычная - для чистых вычислений или синхронных валидаций. Смешивать их нужно осознанно: например, передача async function в Array.prototype.map приведёт к массиву промисов, а не значений.

Пример кода

JAVASCRIPT
// Обычная функция - синхронное выполнение
function syncAdd(a, b) {
return a + b; // сразу число
}
const result = syncAdd(2, 3); // 5
// Async функция - всегда возвращает Promise
async function asyncAdd(a, b) {
return a + b; // обёрнуто в Promise.resolve(5)
}
const promiseResult = asyncAdd(2, 3); // Promise { 5 }
promiseResult.then(val => console.log(val)); // 5
// Пример с await - приостановка выполнения
async function fetchData(url) {
try {
const response = await fetch(url);
return response.json();
} catch (error) {
console.error('Ошибка:', error);
throw error;
}
}
// Без async - нужно явно цепочку промисов
function fetchDataSync(url) {
return fetch(url)
.then(response => response.json())
.catch(error => {
console.error('Ошибка:', error);
throw error;
});
}

Как отвечать на собеседовании

Начни с ключевого отличия - возвращаемое значение и поддержка await. Затем углубись в детали: как async function влияет на event loop, почему она не блокирует поток, но создаёт микротаски. Упомяни, что async function - это синтаксический сахар над генераторами и Promise, и что она не делает код быстрее, а только удобнее. Приведи пример, когда async function может быть избыточной (например, если внутри нет await). Покажи понимание граничных случаев: async function без await, ошибки в async function, комбинация с Promise.all.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание асинхронной модели JavaScript и event loop.
  • Знание внутреннего устройства async/await (связь с Promise и генераторами).
  • Умение выбирать правильный инструмент для задачи (async vs sync).
  • Осознание trade-off: читаемость vs производительность, стек вызовов при await.
  • Способность объяснить сложную тему простыми словами с примерами.

Типичные ошибки

  • Утверждение, что async function делает код многопоточным или параллельным - это не так, она лишь управляет порядком выполнения.
  • Забывание, что async function всегда возвращает Promise, даже если return undefined.
  • Использование await на верхнем уровне модуля без поддержки top-level await.
  • Передача async function в методы массивов (map, forEach) без обработки промисов.
  • Ожидание, что async function может быть вызвана с new - это вызовет TypeError.
  • Игнорирование того, что await приостанавливает только текущую async функцию, а не весь поток.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью