猿问

Express 中间件中的异步/等待

我无法理解如何在 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 代码。我想太多了对吧?


PIPIONE
浏览 222回答 3
3回答

HUWWW

并且永远不要在这个返回的 Promise 上调用 then()。使用这种模式是因为我们不依赖中间件函数的任何返回值吗?是否可以只返回 Promises 而从不调用 then() 来获取它们的值,因为 Express 中的中间件没有返回有意义的值?是的,如果您要跟踪的只是它是否被拒绝,因为它处理自己的成功完成,但您需要单独处理错误,那么您可以使用.catch()这实际上是您正在做的事情。这可以。如果我经常这样做,我会切换到像 Koa 这样的承诺友好型框架,或者我会添加自己的承诺感知中间件注册。例如,下面是 Express 的一个附加组件,它为您提供了 Promise-aware 中间件:// promise aware middleware registration// supports optional path and 1 or more middleware functionsapp.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);}然后,要使用这个可感知承诺的中间件注册,您只需像这样注册它:app.useP(async (req, res, next) => {  req.user = await User.findUser(req.body.id);  next();});而且,任何被拒绝的承诺都会自动为您处理。这是一个更高级的实现。把它放在一个名为的文件中express-p.js:const express = require('express');// promise-aware handler substitutefunction 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()在您创建的应用程序对象或您创建的任何路由器对象上。此代码修改原型,因此您在加载此模块后创建的任何应用程序对象或路由器对象将自动具有所有这些承诺感知方法。

慕勒3428872

你在做什么是绝对好的。但对于那些想得太多的人来说,有一个简单的解决方案。只需重新编写asyncHandler.const asyncHandler = fn => (req, res, next) => {     fn(req, res, next)     .catch(next);}                                       我们不需要Promise.resolve()在asyncHandler. 因为fn是一个async函数,所以它返回一个承诺。catch()如果函数内部有错误,我们就可以承诺。在这里我们没有从asyncHandler函数返回任何东西,因为我们不需要。

开心每一天1111

您可以为此使用 lib express-async-errors。它修补express没有问题。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答