Skip to main content
Практика завдань

Як обробляти async/await в обробниках маршрутів Express.js?

Async/Await в Express.js

Express був спроектований до того, як з'явилися async/await. За замовчуванням, Express не перехоплює необроблені відхилення Promise з асинхронних обробників маршрутів — вони тихо зривають ваш додаток або викликають попередження про необроблені відхилення.


Проблема

js
// ❌ ЛОМАНИЙ — необроблене відхилення Promise! app.get('/users', async (req, res) => { const users = await User.findAll(); // викидає? Express цього не перехоплює! res.json(users); });

Якщо User.findAll() відхиляється, помилка не передається обробнику помилок Express.


Рішення 1: try/catch + next(err)

js
// ✅ Правильно — але громіздко app.get('/users', async (req, res, next) => { try { const users = await User.findAll(); res.json(users); } catch (err) { next(err); // передати обробнику помилок } });

Це працює, але написання try/catch в кожному обробнику є нудним.


Рішення 2: обгортка asyncHandler

js
// utils/asyncHandler.js const asyncHandler = (fn) => (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; module.exports = asyncHandler; // Чисті обробники маршрутів! const asyncHandler = require('../utils/asyncHandler'); app.get('/users', asyncHandler(async (req, res) => { const users = await User.findAll(); res.json(users); })); app.post('/users', asyncHandler(async (req, res) => { const user = await User.create(req.body); res.status(201).json(user); }));

Рішення 3: express-async-errors (Monkey-Patch)

bash
npm install express-async-errors
js
// Імпортуйте ОДИН раз на початку app.js require('express-async-errors'); // Тепер асинхронні помилки автоматично передаються в next()! app.get('/users', async (req, res) => { const users = await User.findAll(); // якщо викидає → йде до обробника помилок res.json(users); });

Це внутрішньо патчує Express. Обгортка не потрібна.


Рішення 4: Express 5 (Автоматично)

Express 5 (в даний час RC) обробляє асинхронні помилки нативно:

bash
npm install express@next
js
// Express 5 — асинхронні помилки автоматично передаються в next() app.get('/users', async (req, res) => { const users = await User.findAll(); res.json(users); });

Паралельні асинхронні операції

js
app.get('/dashboard', asyncHandler(async (req, res) => { // ❌ Послідовно — повільно! (кожен чекає попередній) const users = await fetchUsers(); const posts = await fetchPosts(); const stats = await fetchStats(); // ✅ Паралельно — всі виконуються одночасно const [users, posts, stats] = await Promise.all([ fetchUsers(), fetchPosts(), fetchStats() ]); res.json({ users, posts, stats }); }));

Обробка тайм-аутів

js
function withTimeout(promise, ms = 5000) { const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`Запит перевищив час очікування після ${ms}ms`)), ms) ); return Promise.race([promise, timeout]); } app.get('/slow', asyncHandler(async (req, res) => { const data = await withTimeout(slowExternalAPI(), 3000); res.json(data); }));

Найкращі практики

  1. Завжди використовуйте обгортку asyncHandler АБО express-async-errors
  2. Ніколи не приховуйте помилки — завжди викликайте next(err) або дозвольте обгортці зробити це
  3. Використовуйте Promise.all() для незалежних асинхронних операцій (швидше)
  4. Встановлюйте тайм-аути для викликів зовнішніх API
  5. Використовуйте Express 5 для нових проектів — нативна підтримка асинхронності

Резюме

Express не обробляє асинхронні помилки автоматично. Використовуйте обгортку asyncHandler, express-async-errors або переходьте на Express 5, щоб безпечно використовувати async/await у ваших обробниках маршрутів. Завжди передавайте помилки в next(err), щоб ваш центральний обробник помилок міг їх обробити.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань