异步错误捕获器包装函数导致我返回的承诺未定义

时间:2021-01-30 20:41:47

标签: javascript node.js asynchronous promise

我正在构建一个 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 翘曲器的同时做到这一点?解释为什么删除 catchAsync 包装器可以解决这个问题也很好。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

但是,我认为主要问题是您在 catchAsync 中使用了 createTokensAndCookies。请注意,您实际上传递了一个只有 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 实际上会返回一个承诺,当出现问题时会失败。这是人们在阅读代码时所期望的,它使函数更具可重用性。