在你的路由中使用 async/await,并在不拖垮服务器的前提下处理异步错误。
在 Kodokon 中打开本课你真实的路由不会返回内存里的数组:它们要读取文件、查询数据库、调用其他 API。所有这些操作都是异步的。从 JavaScript 课程起你就认识 async/await 了;我们来看看如何在服务器里干净利落地使用它们。第一个好消息:一个路由函数可以是 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 存在。如果读取失败,promise 会被拒绝,而根据 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) 会把错误交给集中式错误处理器。它是一个带四个参数的中间件,声明在所有路由之后。一个统一记录和格式化错误的地方:这正是一个可维护的 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);
}
});async 路由里,对于被 catch 捕获的错误,你该怎么做?console.log 记录它,然后继续next(error),把它交给错误处理器await 把它们串起来Promise.all 让它们一起启动setTimeouterr 排在第一位errorHandler