Асинхронність у JavaScript: проміси, async/await і патерни

03.04.2026 0 By AdminA

Чому асинхронність важлива

У сучасних вебдодатках асинхронні операції — запити до сервера, читання файлів, таймери та обробка подій — становлять основу взаємодії з користувачем. Розуміння того, як JavaScript обробляє асинхронність, допомагає писати більш передбачуваний, швидкий і надійний код.

Базові поняття: цикл подій, стек і черги

JavaScript використовує однотредовий модель виконання з циклом подій. Основні компоненти цієї моделі:

  • Стек викликів (call stack): виконує синхронні функції.
  • Web APIs: браузерні або середовищні сервіси, що виконують асинхронну роботу (наприклад, fetch, setTimeout).
  • Черги задач (macrotasks) і мікротасків (microtasks): місця, куди ставляться колбеки для подальшого виконання.

Розрізнення мікротасків і макротасків впливає на порядок виконання обробників і може призвести до неочевидної поведінки, якщо його не враховувати.

Проміси: основи

Проміс — це об’єкт, який представляє результат асинхронної операції. Його стан може бути pending, fulfilled або rejected. Основні методи: then, catch і finally.

// Приклад промісу
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log('Дані:', data))
  .catch(err => console.error('Помилка:', err))

Async/await: синтаксичний цукор над промісами

Async/await робить асинхронний код схожим на синхронний, спрощуючи читання і обробку помилок.

async function loadData() {
  try {
    const response = await fetch('/api/data')
    const data = await response.json()
    console.log('Дані:', data)
  } catch (err) {
    console.error('Помилка:', err)
  }
}

Мікротаски vs макротаски

Проміси ставлять виконання в чергу мікротасків, яка обробляється перед наступною макрозадачею. Це означає, що проміс може виконатися перед setTimeout навіть якщо setTimeout має нульову затримку.

console.log('start')
setTimeout(() => console.log('timeout'), 0)
Promise.resolve().then(() => console.log('promise'))
console.log('end')
// Очікуваний порядок: start, end, promise, timeout

Патерни асинхронності

Ось набір корисних підходів для роботи з асинхронними операціями:

  • Паралельне виконання з Promise.all — підходить для незалежних операцій, коли потрібні всі результати.
  • Promise.allSettled — коли потрібно отримати результати незалежно від помилок.
  • Promise.race — коли потрібен перший результат або таймаут.
  • Послідовне виконання — використовувати цикл з await для крокової обробки з контролем порядку.
  • Обмежена паралельність (concurrency limit) — важливий патерн для запитів до API, щоб не перевантажувати сервер.
  • AbortController для скасування запитів — дозволяє відміняти fetch та інші операції.

Приклад обмеження паралельності

async function mapWithLimit(items, limit, handler) {
  const results = []
  const executing = []
  for (const item of items) {
    const p = Promise.resolve().then(() => handler(item))
    results.push(p)
    executing.push(p)
    if (executing.length >= limit) {
      await Promise.race(executing)
      // очищаємо виконані проміси
      executing.splice(executing.findIndex(e => e.done), 1)
    }
  }
  return Promise.all(results)
}

Практичні поради

  • Завжди обробляйте помилки: використовувати catch або try/catch в async-функціях.
  • Не блокувати основний потік важкими синхронними операціями; переміщуйте їх в воркери при потребі.
  • Враховуйте порядок мікро- і макротасків при налагодженні несподіваної поведінки.
  • Для скасування довгих операцій застосовуйте AbortController або власні таймаути.
  • Документуйте очікувану модель виконання в коді, щоб колеги розуміли обмеження та припущення.

Висновок

Асинхронність в JavaScript — не просто механіка викликів, а набір концепцій, які визначають, як ваш код реагує на події й ресурси. Розуміння промісів, async/await, мікро- та макротасків, а також патернів обробки дозволить писати більш передбачуваний і продуктивний код. Починайте з базових прикладів, поступово вводьте патерни обмеження паралельності й скасування, і завжди тестуйте поведінку при різних затримках мережі та навантаженні.

Comments

comments