【问题标题】:asynchronous error catcher wrapper function causing my returned promise to be undefined异步错误捕获器包装函数导致我返回的承诺未定义
【发布时间】:2021-01-31 18:32:31
【问题描述】:

我正在构建一个 api 并尝试使用 req.cookie 创建一些 cookie。

最初我遇到了一个问题,因为在我的同步代码中发出响应之前,cookie 并未全部设置好:

const createTokensAndCookies = catchAsync(async (req, res) => {
    const promises = [];
    promises.push(jwtToken.sign({ id: req.user._id }));
    promises.push(jwtRefreshToken.create());
    promises.push(csrfToken.create());
    const tokens = await Promise.all(promises);
    //create coookies
    jwtCookie.create(req, res, tokens[0]);
    jwtRefreshCookie.create(req, res, tokens[1]);
    csrfCookie.create(req, res, tokens[2]);

});

然后在路由处理程序中调用此函数,并在下一行调用res.send()

为了解决我提出的问题 createTokensAndCookies 返回一个承诺。所以我的代码是:

const createTokensAndCookies = catchAsync(async (req, res) => {
    const promises = [];
    promises.push(jwtToken.sign({ id: req.user._id }));
    promises.push(jwtRefreshToken.create());
    promises.push(csrfToken.create());
    const tokens = await Promise.all(promises);
    //create coookies
    return new Promise((resolve, reject) => {
        jwtCookie.create(req, res, tokens[0]);
        jwtRefreshCookie.create(req, res, tokens[1]);
        csrfCookie.create(req, res, tokens[2]);
        resolve();
    });
});

路由处理程序:

exports.signUp = catchAsync(async (req, res, next) => {
    //get only certain variables out of req object
    const { body } = req;

    const user = await User.create({
        name: body.name,
        email: body.email,
        password: body.password,
        passwordConfirmation: body.passwordConfirmation,
    });
    req.user = user;
    createTokensAndCookies(req, res).then(() => {
        res.status(201).json({
            status: 'success',
        });
    });
});

还有catchAsync 包装器:

module.exports = (fn) => (req, res, next) => {
    fn(req, res, next).catch(next);
};

我现在收到以下错误: Cannot read property 'then' of undefined

有趣的是,当我删除 catchAsync 包装器时,一切正常,并且在创建所有 cookie 之前不会发送响应。

有谁知道我如何在保持catchAsync warpper 的同时做到这一点?解释为什么删除 catchAsync 包装器可以解决问题也很好。

【问题讨论】:

  • "为了解决我让createTokensAndCookies 返回一个承诺的问题" - async 函数已经确实返回了一个承诺(它是使用await),添加return new Promise((resolve, reject) => { … resolve(); }); 并没有任何改变。
  • "有谁知道我如何在保持catchAsync warpper 的同时做到这一点?" - 不,这没有任何意义。为什么要将它保留在 createTokensAndCookies 定义附近?您应该在路由处理程序周围使用catchAsync

标签: javascript node.js asynchronous promise


【解决方案1】:

您的错误似乎发生在这一行:

createTokensAndCookies(req, res).then(() => {

问题是createTokensAndCookies() 没有返回任何东西。解决此特定问题的简单修复方法可能是您像这样更改它以返回一个承诺:

module.exports = (fn) => (req, res, next) => {
    return fn(req, res, next).catch(next);
};

但是,我认为主要问题是您在createTokensAndCookies 中使用了catchAsync。请注意,您实际上传递的函数只有 2 个参数,而预期为 3 个。抓两次似乎是多余的。您可以并且应该只传递从路由处理程序内的createTokensAndCookies(没有catchAsync)返回的承诺。所以去掉catchAsync:

const createTokensAndCookies = async (req, res) => {
    const promises = [];
    promises.push(jwtToken.sign({ id: req.user._id }));
    promises.push(jwtRefreshToken.create());
    promises.push(csrfToken.create());
    const tokens = await Promise.all(promises);
    //create cookies
    jwtCookie.create(req, res, tokens[0]);
    jwtRefreshCookie.create(req, res, tokens[1]);
    csrfCookie.create(req, res, tokens[2]);
};

并像这样更改路由处理程序:

exports.signUp = catchAsync(async (req, res, next) => {
    // ...
    return createTokensAndCookies(req, res).then(() => {
        res.status(201).json({
            status: 'success',
        });
    });
});

我怀疑您想将catchAsync 保留在createCookiesAndTokens 中,因为您在其他地方使用它作为路由处理程序。如果是这种情况,只需将其包装在 catchAsync 中即可。这样createCookiesAndTokens 实际上会返回一个在出现问题时会失败的承诺。这是人们在阅读代码时所期望的,它使函数更具可重用性。

【讨论】:

    猜你喜欢
    • 2022-01-26
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多