node.js - Asnyc Express Midleware 工作的原因是什么?
问题描述
嗨,我是 Express/Node 的新手,正在寻找指导和解释。
如果我有一个 asyc 函数作为中间件,这本质上会立即返回一个承诺。让我们模拟一个函数。
async function verifyToken() {
try {
await API call...
next() // <-- continue to the next middleware if the api call was successful
} catch (err) {
// catch exceptions from api call
}
}
我现在想知道当我像这样使用这个功能时:
this.router.get("/test", verifyToken, (req, res) => {
res.send("GET TEST");
});
如果 verifyToken 是异步的,这是否意味着它被立即调用返回一个 Promise 然后节点继续执行?异步方法如何作为中间件工作?
解决方案
如果 verifyToken 是异步的,这是否意味着它被立即调用返回一个 Promise 然后节点继续执行?异步方法如何作为中间件工作?
你是对的,该async
函数一旦到达内部就会立即返回一个承诺await
。但是,即使 Express 没有注意那里的返回承诺,由于 Express 的设计,它仍然可以正常工作。
Express 在其设计中预计需要异步中间件(无论是否使用 Promise)。因此,它调用您的中间件,将req
, 和res
对象和next
回调传递给它,然后什么也不做。字面上没什么。在这一点上进行进一步处理,直到您执行以下两件事之一 - 发送带有类似res.send()
或调用的响应next()
。如果您发送响应,那是非常不言自明的。如果您调用next()
,那么它会告诉 Express 遵循此请求的处理程序链并找到下一个匹配的请求处理程序并调用它。
因此,以下是此路线匹配时的步骤:
async function verifyToken(req, res, next) {
try {
await API call...
next() // <-- continue to the next middleware if the api call was successful
} catch (err) {
// catch exceptions from api call
}
}
this.router.get("/test", verifyToken, (req, res) => {
res.send("GET TEST");
});
- nodejs 首先调用
verifyToken()
并传递它req, res, next
。 - 该函数命中
await
,进行 API 调用,暂停该函数的进一步执行,然后立即返回一个未决的承诺 - 返回返回到 Express,它只是返回到任何网络事件通知它有关传入请求的信息,并且没有其他事情可做。
- 然后,有一段时间什么都没有发生。
- 然后,您的 API 调用在某个时间点完成,等待的承诺得到解决。这将在
await
. - 该调用
next()
返回到 Express 中,并使用next()
回调闭包中的数据,它知道接下来要调用哪个处理程序,并在您的路由中调用最终请求处理程序,该处理程序调用res.send()
. - 该处理程序返回并且 Express 完成。由于您没有
next()
从最后一个处理程序调用,Express 将不再处理该请求。
Express 是不久前设计的,因此不是天生的承诺意识。但是,它在设计时考虑到了异步操作,因此 Promise 仍然可以很好地与框架一起使用——您只需将 Promise 事件处理程序连接到适当的 Express 回调。因为 express 没有观察你的async
函数返回的 promise,所以你必须确保你自己捕获所有的拒绝,因为 Express 不会为你捕获它们。
Express 有一个名为 koa 的表亲,它更多地围绕 Promise 进行设计,并且对被拒绝的 Promise 具有自动错误处理功能。
推荐阅读
- r - 组合多个大序列的所有元素
- apache-spark - Spark 错误 java.lang.NoSuchFieldError: SPARK_RPC_SERVER_ADDRESS 上的 Hive
- makefile - 基于目录存在的 Makefile 变量分配
- python-3.x - 如何在 AWS SageMaker(Jupyter Notebook)中使用 cx_Oracle
- android - Observable subscribe 没有被调用相同的值
- java - 单元测试仅更新某些属性的方法
- python - 通过计算0在python中groupby之后的列中出现的次数来实现子集
- laravel - 如何对两列进行验证
- macos - macOS 中的应用程序拦截器 1Focus 如何阻止(最小化)其他应用程序?
- java - 如何在构造函数中访问 application.properties 值