我很难理解如何在Express中正确编写使用async/await的中间件,但在执行后不会让Promise漂浮在以太网上。我已经阅读了大量的博客和StackOverflow帖子,似乎对于在async/await中间件中使用以下模式有一些共识:
const asyncHandler = fn => (req, res, next) =>
Promise
.resolve(fn(req, res, next))
.catch(next)
app.use(asyncHandler(async (req, res, next) => {
req.user = await User.findUser(req.body.id);
next();
}));
我知道这使得在所有aysnc路由处理程序中不必使用try… catch逻辑成为可能,并且它确保(async(req, res, next)=返回的Promise
Promise
.resolve(fn(req, res, next))
.catch(next)
再也没有对返回的Promise调用then()。使用此模式是因为我们不依赖中间件函数的任何返回值吗?只返回Promises而不调用then()来获取它们的值,这样可以吗?因为Express中的中间件没有返回有意义的值?
我知道async/await允许我们处理异步代码并轻松处理返回的值,但在Express中间件中,我们只剩下顶级异步,它解析为Promise,然后我们用Promise.resolve()解析,但它仍然解析为Promise…
此外,我知道这个问题有第三方解决方案,你可以使用另一个框架,如Koa。我只是想了解如何在Express中正确地做到这一点,因为我对Node后端开发仍然相对陌生,并且希望在了解基础知识之前只关注Express。
我的初步解决方案是仅在非中间件函数中使用异步/await,然后在实际中间件中返回的 Promise 上调用 then(),这样我就可以确定我没有做任何淘气的事情,就像这样:
app.use((req, res, next) => {
User.findUser(req.body.id)
.then(user => {
req.user = user;
next();
})
.catch(next)
});
这对我来说没什么,但是我一直看到到处都是asyncWrapper代码。我想多了,对吗?
您可以将 lib 用于此快速异步错误
。它补丁快递
没有问题。
你所做的绝对没问题。但是对于那些过度思考的人来说,有一个简单的解决方法。只需重写< code >异步处理程序。
const asyncHandler = fn => (req, res, next) => {
fn(req, res, next)
.catch(next);
}
我们不需要使用Promise。
asyncHandler上的resolve()
。因为fn
是一个异步
function,所以它返回一个promise。如果函数内部有错误,我们可以只使用catch()
来保证。
在这里,我们没有从
asyncHandler
函数返回任何东西,因为我们不需要这样做。
并且从不在这个返回的promise上调用then()。使用这种模式是因为我们不依赖中间件函数的任何返回值吗?
是否可以只返回Promises,而不调用that()来获取它们的值,因为Express中的中间件没有返回有意义的值?
是的,如果您只想跟踪它是否被拒绝,因为它处理自己的成功完成,但您需要单独处理错误,那么您只需使用。catch()
,这就是您正在做的事情。这很好。
如果我经常这样做,我要么切换到像Koa这样的promise友好框架,要么添加我自己的promise感知中间件注册。例如,Express的一个附加组件为您提供了支持promise的中间件:
// promise aware middleware registration
// supports optional path and 1 or more middleware functions
app.useP = function(...args) {
function wrap(fn) {
return async function(req, res, next) {
// catch both synchronous exceptions and asynchronous rejections
try {
await fn(req, res, next);
} catch(e) {
next(e);
}
}
}
// reconstruct arguments with wrapped functions
let newArgs = args.map(arg => {
if (typeof arg === "function") {
return wrap(arg);
} else {
return arg;
}
});
// register actual middleware with wrapped functions
app.use(...newArgs);
}
然后,要使用这个promise感知中间件注册,您只需像这样注册它:
app.useP(async (req, res, next) => {
req.user = await User.findUser(req.body.id);
next();
});
而且,任何被拒绝的promise都会自动为你处理。
这是一个更高级的实现。把它放在一个名为express-p.js
的文件中:
const express = require('express');
// promise-aware handler substitute
function handleP(verb) {
return function (...args) {
function wrap(fn) {
return async function(req, res, next) {
// catch both synchronous exceptions and asynchronous rejections
try {
await fn(req, res, next);
} catch(e) {
next(e);
}
}
}
// reconstruct arguments with wrapped functions
let newArgs = args.map(arg => {
if (typeof arg === "function") {
return wrap(arg);
} else {
return arg;
}
});
// register actual middleware with wrapped functions
this[verb](...newArgs);
}
}
// modify prototypes for app and router
// to add useP, allP, getP, postP, optionsP, deleteP variants
["use", "all", "get", "post", "options", "delete"].forEach(verb => {
let handler = handleP(verb);
express.Router[verb + "P"] = handler;
express.application[verb + "P"] = handler;
});
module.exports = express;
然后,在您的项目中,而不是这样:
const express = require('express');
app.get(somePath, someFunc);
使用此:
const express = require('./express-p.js');
app.getP(somePath, someFunc);
然后,您可以自由使用这些方法中的任何一种,它们会自动处理从routes返回的拒绝promise:
.useP()
.allP()
.getP()
.postP()
.deleteP()
.optionsP()
在您创建的应用程序对象或您创建的任何路由器对象上。此代码修改原型,因此您在加载此模块后创建的任何应用程序对象或路由器对象都将自动具有所有这些Promise-ware方法。
我需要修改一个现有的程序,它包含以下代码: 但这在我看来非常奇怪,首先是在select中使用和。根据斯蒂芬·克利里的回答,我应该能够放弃这些。 然后第二个,它选择结果。这是不是意味着任务根本不是异步的,而是同步执行的(这么多的努力是徒劳无功的),或者任务是异步执行的,当它完成后,查询的其余部分将被执行? 我是否应该按照Stephen Cleary的另一个答案,像下面这样编写上述代码: 而且像这样完
但是,了解node.js事件循环会发现: 当然,在后端,有用于DB访问和进程执行的线程和进程。 在C#中,编写带有标记的函数和带有的调用就足够了,这样.NET就可以将它放在另一个线程中。但是,node.js中组织方式不同的东西让我很困惑,async/await函数仍然会阻塞主线程。
问题内容: 我有一个像防火墙/调度程序一样位于其他微服务前面的节点应用程序,它使用如下所示的中间件链: 但是对于特定的GET路由,我想跳过所有这些,除了rateLimiter和proxy。他们是否可以使用:except /:only来设置类似Rails before_filter的过滤器? 问题答案: 即使expressjs中没有内置的中间件过滤器系统,您也可以通过至少两种方法来实现。 第一种方法
问题内容: 我有一个Express中间件,因为我想在其中使用中间件来清理我的代码。 问题在于,当它拒绝时,它不会进入我的错误中间件,但是如果我删除了关键字,并且在中间件中,它将删除。 所以我得到的不是输入我的错误处理中间件,而是如何让错误冒泡并表达处理它? 问题答案: 问题是当它拒绝时,它不会进入我的错误中间件,但是如果我删除了async关键字并扔进了中间件中,它就会去。 目前不支持诺言,将来的版
任务或任务 我们也可以定义自己的可实现对象。对象应具有以下资格。 < li >它有一个GetAwaiter()方法(实例方法或扩展方法); < li >其GetAwaiter()方法返回一个Awaiter。在下列情况下,对象是一个标识符: < ul > < li >它实现INotifyCompletion或ICriticalNotifyCompletion接口; < li >它有一个IsCompl
在工作区块链的证明中,与链同步的过程与共识保持最新是相同的:下载块,并寻找工作总量最多的块。在权益证明中,共识过程更为复杂,因为它涉及到节点之间的轮询通信,以确定下一步应该提交哪个块。从头开始使用这个过程来同步区块链可能需要很长时间。只下载块并检查验证者的默克尔树要比运行实时共识 gossip 协议快得多。 使用快速同步 为了支持更快的同步,tendermint 提供了一种 fast-sync 模