Async Function — скрытая стоимость

async/await — не бесплатный. Каждое await создаёт промис, добавляет микротаску в queue и заставляет V8 перестраивать стек. В горячем коде эта стоимость суммируется.

Что происходит на каждое await

  1. Создаётся Promise (даже если функция уже завершилась синхронно).
  2. Текущий фрейм сохраняется в suspend resume frame.
  3. Микротаска добавляется в queue.
  4. На след. тике микротаски — фрейм восстанавливается.

Сравнение

// 100% синхронно, без накладных
function syncFn() { return 42; }

// Эквивалент через async — оверхед на каждый вызов
async function asyncFn() { return 42; }
// Возвращает Promise<42>, даже без await

// Хуже всего — await на не-thenable
async function bad() {
  const x = await 42;          // микротаска без причины
  return x;
}

Когда async вреден

  • Hot цикл на миллион итераций — НЕ оборачивай шаги в await.
  • Чистая синхронная функция — не делай её async «на всякий случай».
  • Promise-цепочка из коротких await может быть медленнее единого .then.

Когда уместен

  • Реальный I/O (сеть, ФС).
  • Параллельные операции через Promise.all.
  • Читаемость важнее микро-оптимизации.

Подводные камни

  • for await ... of — последовательно (один await за итерацию).
  • Параллельный обход — Promise.all(arr.map(async ...)).
  • try/catch вокруг await дешевле, чем .catch цепочка, но всё ещё дороже синхронного.

Источники

См. также