Используй async/await в своих маршрутах и обрабатывай асинхронные ошибки, не роняя сервер.
Открыть этот урок в KodokonТвои настоящие маршруты не возвращают массивы из памяти: они читают файлы, обращаются к базе данных, вызывают другие API. Все эти операции асинхронные. async/await ты знаешь ещё с направления JavaScript; давай посмотрим, как применять их аккуратно на сервере. Первая хорошая новость: функция маршрута может быть async.
import express from "express";
import { readFile } from "node:fs/promises";
const app = express();
app.get("/report", async (req, res) => {
const raw = await readFile("report.json", "utf8");
res.json(JSON.parse(raw));
});
app.listen(3000);Этот код работает... пока report.json существует. Если чтение упадёт, промис будет отклонён, и, в зависимости от версии Express, запрос останется без ответа или ошибка утечёт в логи. Профессиональное правило: каждый асинхронный маршрут обрабатывает свои ошибки, через try/catch и next(error).
app.get("/report", async (req, res, next) => {
try {
const raw = await readFile("report.json", "utf8");
res.json(JSON.parse(raw));
} catch (error) {
next(error);
}
});next(error) передаёт ошибку в централизованный обработчик ошибок. Это middleware с четырьмя параметрами, объявленный после всех маршрутов. Одно-единственное место, где ошибки логируются и форматируются: именно это отличает поддерживаемый API от проекта выходного дня.
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
error: "Internal server error"
});
});Остался ещё один рефлекс: параллельность. Две независимые операции, выстроенные в цепочку из двух await, выполняются одна за другой. Promise.all запускает их вместе: время ответа равно времени самой медленной, а не сумме двух.
async function fetchUsers() {
return [{ id: 1, name: "Ada" }];
}
async function fetchTasks() {
return [{ id: 1, title: "Review the code" }];
}
app.get("/dashboard", async (req, res, next) => {
try {
const [users, tasks] = await Promise.all([
fetchUsers(),
fetchTasks()
]);
res.json({ users, tasks });
} catch (error) {
next(error);
}
});catch, внутри async-маршрута?console.log и идёшь дальшеnext(error), чтобы передать её обработчику ошибокawait подрядPromise.allsetTimeout между нимиerr идёт первымerrorHandler