gpt4 book ai didi

javascript - Express 中间件中的异步/等待

转载 作者:行者123 更新时间:2023-12-03 07:05:07 26 4
gpt4 key购买 nike

我无法理解如何在 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函数已解决,但我的问题是我们从 asyncHandler 的 Promise.resolve() 调用中返回了一个 Promise:
Promise
.resolve(fn(req, res, next))
.catch(next)

并且永远不要在这个返回的 Promise 上调用 then()。使用这种模式是因为我们不依赖中间件函数的任何返回值吗?是否可以只返回 Promises 而从不调用 then() 来获取它们的值,因为 Express 中的中间件没有返回有意义的值?

我知道 async/await 允许我们处理异步代码并轻松处理返回的值,但在 Express 中间件中,我们留下了顶级异步,它解析为 Promise,然后我们使用 Promise.resolve 解析(),但它仍然解析为 Promise...

另外,我知道这个问题有 3rd 方解决方案,你可以使用另一个框架,比如 Koa。我只是想了解如何在 Express 中正确执行此操作,因为我对使用 Node 进行后端开发还比较陌生,并且希望只专注于 Express,直到我掌握了基础知识。

我暂定的解决方案是仅在非中间件函数中使用 async/await,然后在实际中间件中对返回的 Promises 调用 then() ,这样我就可以确定我没有做任何顽皮的事情,例如:
app.use((req, res, next) => {
User.findUser(req.body.id)
.then(user => {
req.user = user;
next();
})
.catch(next)
});

这对我来说很好,但我一直在到处看到 asyncWrapper 代码。我想太多了对吧?

最佳答案

And never calling then() on this returned Promise. Is this pattern used because we aren't relying on any returned value from middleware functions?

Is it OK to just return Promises and never call then() on them to get their value, since there is no meaningful value returned from middleware in Express?


是的,如果您只想跟踪它是否被拒绝,因为它处理自己的成功完成,但您需要单独处理错误,那么您可以使用 .catch()这实际上就是您正在做的事情。这可以。

如果我经常这样做,我会切换到像 Koa 这样的 promise 友好型框架,或者我会添加自己的 promise 感知中间件注册。例如,下面是 Express 的一个附加组件,它为您提供了 Promise-aware 中间件:
// 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);
然后,您可以自由使用这些方法中的任何一种,它们会自动处理从路由返回的被拒绝的 Promise:
 .useP()
.allP()
.getP()
.postP()
.deleteP()
.optionsP()
在您创建的应用程序对象或您创建的任何路由器对象上。此代码修改原型(prototype),因此您在加载此模块后创建的任何应用程序对象或路由器对象将自动具有所有这些 promise 感知方法。

关于javascript - Express 中间件中的异步/等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61086833/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com