在 Express 中使用 Async/await
你有没有注意到,在 Express 请求处理程序中写了很多异步代码?这很正常,因为你需要与数据库、文件系统和其他 API 进行通信。
当你有大量异步代码时,使用 Async/await 会很有帮助。它使你的代码更容易理解。
今天,我想分享如何在 Express 请求处理程序中使用 async/await。
注意:在继续之前,你需要了解什么是 Async/await。如果你不知道,可以阅读这篇文章了解更多信息。
在请求处理程序中使用 Async/await
要使用 Async/await,您需要在定义请求处理程序时使用async
关键字。(注意:这些请求处理程序被称为“控制器”。我更喜欢称之为请求处理程序,因为请求处理程序更明确。)
app.post("/testing", async (req, res) => {
// Do something here
});
一旦有了async
关键字,您就可以await
立即在代码中执行某些操作。
app.post("/testing", async (req, res) => {
const user = await User.findOne({ email: req.body.email });
});
处理异步错误
假设你想通过 POST 请求创建一个用户。要创建用户,你需要传入一个firstName
和一个email
地址。你的 Mongoose Schema 如下所示:
const userSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
firstName: {
type: String,
required: true
}
});
这是您的请求处理程序:
app.post("/signup", async (req, res) => {
const { email, firstName } = req.body;
const user = new User({ email, firstName });
const ret = await user.save();
res.json(ret);
});
现在,假设您向服务器发送一个缺少电子邮件地址的请求。
fetch('/signup', {
method: 'post'
headers: { 'Content-Type': 'application/json' }
body: JSON.stringify({
firstName: 'Zell'
})
}
此请求导致错误。很遗憾,Express 无法处理此错误。您将收到如下日志:
要处理异步函数中的错误,您需要先捕获错误。您可以使用 来实现try/catch
。
app.post("/signup", async (req, res) => {
try {
const { email, firstName } = req.body;
const user = new User({ email, firstName });
const ret = await user.save();
res.json(ret);
} catch (error) {
console.log(error);
}
});
接下来,使用参数将错误传递到 Express 错误处理程序中next
。
app.post("/signup", async (req, res, next) => {
try {
const { email, firstName } = req.body;
const user = new User({ email, firstName });
const ret = await user.save();
res.json(ret);
} catch (error) {
// Passes errors into the error handler
return next(error);
}
});
如果您尚未编写自定义错误处理程序,Express 将使用其默认错误处理程序为您处理错误。(尽管我建议您编写自定义错误处理程序。您可以在此处了解更多信息)。
Express 的默认错误处理程序将:
- 将 HTTP 状态设置为 500
- 向请求者发送文本响应
- 在控制台中记录文本响应


处理两个或更多异步错误
如果需要处理两个await
语句,则可以编写以下代码:
app.post("/signup", async (req, res, next) => {
try {
await firstThing();
} catch (error) {
return next(error);
}
try {
await secondThing();
} catch (error) {
return next(error);
}
});
这是不必要的。如果firstThing
导致错误,请求将立即发送到错误处理程序。您不会触发对 的调用secondThing
。如果secondThing
导致错误,firstThing
则不会触发错误。
这意味着:只有一个错误会被发送到错误处理程序。这也意味着我们可以将所有await
语句包装在一个try/catch
语句中。
app.post("/signup", async (req, res, next) => {
try {
await firstThing();
await secondThing();
} catch (error) {
return next(error);
}
});
清理
每个请求处理程序中都包含一条try/catch
语句,这很糟糕。它们使请求处理程序看起来比实际更复杂。
一个简单的方法是将 改为try/catch
promise。这样感觉更友好。
app.post('/signup', async(req, res, next) => {
function runAsync () {
await firstThing()
await secondThing()
}
runAsync()
.catch(next)
})
但为每个 Express 处理程序都写一遍太麻烦了runAsync
。我们可以把它抽象成一个包装函数,然后把这个包装函数附加到每个请求处理程序上。
function runAsyncWrapper (callback) {
return function (req, res, next) {
callback(req, res, next)
.catch(next)
}
}
app.post('/signup', runAsyncWrapper(async(req, res) => {
await firstThing()
await secondThing()
})
Express 异步处理程序
您也不必runAsyncWrapper
每次编写 Express 应用时都编写代码。Alexei Bazhenov创建了一个名为express-async-handler 的包,它能以更健壮的方式完成这项工作。(它确保next
始终是最后一个参数)。
要使用express-async-handler
,您必须先安装它:
npm install express-async-handler --save
在您的应用中使用它:
const asyncHandler = require('express-async-handler')
app.post('/signup', asyncHandler(async(req, res) => {
await firstThing()
await secondThing()
})
我不喜欢写asyncHandler
。它太长了。我最明显的解决办法是缩写asyncHandler
成ash
。
如果你更精通,可以考虑使用Valeri Karpov的@awaitjs/express。它为 Express 添加了和等方法,因此你不必使用。getAsync
postAsync
express-async-handler
感谢阅读。本文最初发布在我的博客上。如果您想阅读更多文章来帮助您成为更优秀的前端开发人员,请订阅我的新闻通讯。
文章来源:https://dev.to/zellwk/using-async-await-in-express-3p77