Асинхронне програмування в JavaScript: практичні патерни та приклади

11.02.2026 0 By AdminA

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

JavaScript працює в однопотоковому середовищі, тому блокування головного потоку призводить до пригальмовування інтерфейсу. Асинхронні механізми дозволяють виконувати операції вводу/виводу, мережеві запити та важку обробку без заморозки UI. Знання патернів асинхронного програмування допомагає писати читабельний, надійний і масштабований код.

Еволюція підходів: колбеки → проміси → async/await

Коротко про три основні підходи:

  • Колбеки — прості, але призводять до труднощів у структурі коду і обробці помилок («callback hell»).
  • Проміси (Promise) — забезпечують ланцюжки викликів і спрощують обробку помилок через catch.
  • Async/await — синтаксичний цукор над промісами, робить асинхронний код більш послідовним і читабельним.

Приклад проблеми з колбеками

readFile('a.txt', function(err, dataA) {
  if (err) return handle(err);
  readFile('b.txt', function(err, dataB) {
    if (err) return handle(err);
    process(dataA, dataB, function(err, result) {
      if (err) return handle(err);
      save(result, function(err) {
        if (err) return handle(err);
        done();
      });
    });
  });
});

Проміси і корисні методи

Проміси вирішують частину проблем, дозволяючи ланцюжити операції і централізовано обробляти помилки. Важливі методи:

  • Promise.all — чекає на виконання всіх промісів, відхиляє при першій помилці.
  • Promise.allSettled — чекає на завершення всіх промісів і повертає статуси виконання.
  • Promise.race — повертає перший проміс, що завершився (успішно або з помилкою).

Приклад: паралельні запити з обробкою всіх результатів

const urls = ['a', 'b', 'c'];
const promises = urls.map(u => fetch(u));
const results = await Promise.allSettled(promises);
results.forEach(r => {
  if (r.status === 'fulfilled') handleSuccess(r.value);
  else handleError(r.reason);
});

Async/await — чистіший синтаксис

Async/await робить асинхронний код схожим на синхронний. Потрібно пам’ятати про try/catch для обробки помилок.

Послідовне виконання

async function processSequence() {
  try {
    const a = await fetchDataA();
    const b = await fetchDataB(a);
    await saveResult(b);
  } catch (err) {
    console.error('Error:', err);
  }
}

Паралельне виконання

Щоб виконати незалежні запити паралельно, збирайте проміси і потім await їх усіх:

const p1 = fetchA();
const p2 = fetchB();
const [a, b] = await Promise.all([p1, p2]);

Корисні патерни та практики

  • Retry з експоненційним бекофом — для тимчасових помилок мережі.
  • Ограничення конкуренції (pooling) — щоб не перевантажувати сервер або не створювати занадто багато одночасних операцій.
  • Використання AbortController для скасування fetch-запитів.
  • Обробка помилок на рівні виклику: логування, повторні спроби або graceful fallback.

Приклад обмеження конкуренції

async function limitedMap(items, handler, limit = 5) {
  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);
      // видалити завершені
      for (let i = executing.length - 1; i >= 0; i--) {
        if (executing[i].settled) executing.splice(i, 1);
      }
    }
  }
  return Promise.all(results);
}

Зауважте: у прикладі потрібна додаткова логіка, щоб позначати проміси як settled, або використовувати готові бібліотеки для семафорів.

Поради для підтримуваного коду

  • Практикуйте централізовану обробку помилок і зрозумілі повідомлення.
  • Використовуйте таймаути та скасування для довгих операцій.
  • Пишіть тести для асинхронних сценаріїв — мокайте таймери і мережу.
  • Документуйте очікувану поведінку при помилках і retry-стратегії.

Висновок

Асинхронність — ключ до ефективних веб-додатків на JavaScript. Розуміння промісів, async/await і відповідних патернів (retry, throttling, cancellation) дозволяє будувати надійну та масштабовану архітектуру. Почніть з чистих абстракцій і невеликих утиліт, щоб спростити повторне використання й тестування.

Comments

comments