Асинхронные обработчики
Многие операции на сервере асинхронные: чтение файла, запрос к базе данных или к другому сайту. Обработчик маршрута может быть async-функцией и ждать результат через await. В Express 5 ошибка внутри такой функции сама попадает в обработчик ошибок — оборачивать код в try...catch не обязательно.
Асинхронный маршрут
Пусть текст страницы «О блоге» хранится в файле content/about.txt в корне проекта. Прочитаем его в контроллере:
// src/controllers/pagesController.js
import { readFile } from 'node:fs/promises';
export async function about(req, res) {
const text = await readFile('content/about.txt', 'utf8');
res.send(`<h1>О блоге</h1><p>${text}</p>`);
}И подключим маршрут в src/app.js:
// src/app.js
import * as pagesController from './controllers/pagesController.js';
app.get('/about', pagesController.about);По адресу /about появится текст из файла. Пока файл читается, сервер не стоит на месте и обслуживает другие запросы.
Что происходит при ошибке
Удалите или переименуйте content/about.txt и снова откройте /about. readFile() вернёт отклонённый промис, а Express 5 заметит это и вызовет обработчик ошибок из прошлого урока. Посетитель увидит «Ошибка сервера», в терминале появится ENOENT: no such file or directory.
Как было в Express 4
В старых проектах можно встретить такую обёртку:
// src/controllers/pagesController.js
export async function about(req, res, next) {
try {
const text = await readFile('content/about.txt', 'utf8');
res.send(`<p>${text}</p>`);
} catch (error) {
next(error);
}
}Express 4 не следил за промисами, и без try...catch ошибка оставалась необработанной. В Express 5 этот код по-прежнему работает, но писать его не нужно.
Когда try...catch всё же нужен
try...catch пишут, когда ошибку нужно не передать дальше, а обработать на месте — например, показать запасной текст:
// src/controllers/pagesController.js
export async function about(req, res) {
let text = 'Скоро здесь будет рассказ о блоге.';
try {
text = await readFile('content/about.txt', 'utf8');
} catch {
// файла нет — оставляем текст по умолчанию
}
res.send(`<h1>О блоге</h1><p>${text}</p>`);
}Теперь без файла страница всё равно откроется со строкой «Скоро здесь будет рассказ о блоге».
Частая ошибка
Express 5 видит только тот промис, который вернул сам обработчик. Если забыть await, функция закончится раньше, чем операция, и ошибка выйдет «мимо» Express: процесс напишет Unhandled promise rejection и может завершиться. Ставьте await перед каждой асинхронной операцией, результат или ошибка которой важны для ответа.