如何处理错误然后立即脱离承诺链?

Jos*_*ery 5 javascript node.js promise express

所以我有一个 Express 应用程序,它使用中间件来解析 JSON POST 请求,然后填充一个req.body对象。然后我有一个承诺链,它使用 Joi 根据模式验证数据,然后将其存储在数据库中。

我想做的是检查这些进程之一之后是否抛出错误,通过发送状态代码进行适当处理,然后完全中止承诺链。我觉得应该有一些非常干净和简单的方法来做到这一点,(也许是某种中断语句?)但我在任何地方都找不到它。这是我的代码。我留下了评论,表明我希望在哪里中止承诺链。

const joi = require("joi");

const createUserSchema = joi.object().keys({
    username: joi.string().alphanum().min(4).max(30).required(),
    password: joi.string().alphanum().min(2).max(30).required(),
});

//Here begins my promise chain 
app.post("/createUser", (req, res) => {
    //validate javascript object against the createUserSchema before storing in database
    createUserSchema.validate(req.body)
        .catch(validationError => {
           res.sendStatus(400);

           //CLEANLY ABORT the promise chain here

           })
        .then(validatedUser => {
            //accepts a hash of inputs and stores it in a database 
            return createUser({
                    username: validatedUser.username,
                    password: validatedUser.password
                })
        .catch(error => {
            res.sendStatus(500);

            //CLEANLY ABORT the promise chain here

        })
        //Only now, if both promises are resolved do I send status 200
        .then(() => {
            res.sendStatus(200); 
            }                 
        )

});
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 5

你不能在中间中止承诺链。它将在链中调用 a.then()或 a稍后(假设两者都存在并且假设您的承诺解决或拒绝)。.catch()

通常,处理此问题的方法是将一个.catch()错误放在链的末尾,它会检查错误类型并采取适当的操作。您没有在链的早期处理错误。你让最后一个.catch()人处理事情。

这是我的建议:

// helper function
function err(status, msg) {
    let obj = new Error(msg);
    obj.status = status;
    return obj;
}

//Here begins my promise chain 
app.post("/createUser", (req, res) => {
    //validate javascript object against the createUserSchema before storing in database
    createUserSchema.validate(req.body).catch(validationError => {
        throw err("validateError", 400)
    }).then(validatedUser => {
            //accepts a hash of inputs and stores it in a database 
            return createUser({
                    username: validatedUser.username,
                    password: validatedUser.password
            }).catch(err => {
                throw err("createUserError", 500);
            });
    }).then(() => {
        // success
        res.sendStatus(200); 
    }).catch(error => {
        console.log(error);
        if (error && error.status) {
            res.sendStatus(error.status);
        } else {
            // no specific error status specified
            res.sendStatus(500);
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

这有几个优点:

  1. 任何错误都会传播到.catch()记录该错误的链末尾的最后一个错误,并且仅在代码中的一个位置发送适当的状态。
  2. 成功仅在发送该状态的一个位置进行处理。
  3. 这可以无限扩展到链条中的更多环节。如果您有更多可能出现错误的操作,它们可以“中止”链的其余部分(最后一个操作除外,.catch()仅通过适当的错误对象进行拒绝)。
  4. 这有点类似于在函数中不要有大量return value语句的设计实践,而是累积结果然后在最后返回它,有些人认为这对于复杂函数来说是一个很好的实践。
  5. 调试时,您可以在一个.then()和一个中设置断点.catch()以查看 Promise 链的最终解决方案,因为整个链都经过了最后一个.then()或最后一个.catch()

  • @JoshuaAvery - 你研究过我的代码建议吗?它处理错误,设置它希望如何处理错误,然后重新抛出错误,以便它会跳转到状态和日志消息已设置的最后一个“.catch()”。这是一种技术。另一种方法是为每个位置抛出单独类型的错误,然后在 .catch() 中使用 switch 语句来检查每种类型的错误。我更喜欢这种机制,因为我认为它可以更好地扩展并将一个操作的所有代码保留在一起。 (2认同)