【问题标题】:How to do proper error handling with async/await如何使用 async/await 进行正确的错误处理
【发布时间】:2019-02-14 02:56:15
【问题描述】:

我正在编写一个 API,但在处理错误时遇到了一些问题。我不确定的是第一个代码 sn-p 是否足够,或者我是否应该将它与第二个代码 sn-p 中的 promise 混合使用。任何帮助将非常感激!

try {
  var decoded = jwt.verify(req.params.token, config.keys.secret);
  var user = await models.user.findById(decoded.userId);
  user.active = true;
  await user.save();
  res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
  next(error);
}

第二个代码sn-p:

try {
      var decoded = jwt.verify(req.params.token, config.keys.secret);
      var user = models.user.findById(decoded.userId).then(() => {

      }).catch((error) => {

      });
      user.active = true;
      await user.save().then(() => {

      }).catch((error) => {

      })
      res.status(201).json({user, 'stuff': decoded.jti});
    } catch (error) {
      next(error);
    }

【问题讨论】:

  • 第一个看起来很好。
  • 我读过一些文章,建议每个请求都需要一个 try/catch 块。这有什么道理吗?
  • 视情况而定。是,如果:您想在每次异步调用后做出不同的反应吗? (例如,每个错误案例的不同响应)否如果:您是否希望仅在解决所有异步调用后才继续响应?

标签: node.js express asynchronous error-handling promise


【解决方案1】:

答案是:视情况而定

捕捉每一个错误

如果您想对每个错误做出不同的反应,这是有道理的。 例如:

 try {
        let decoded;
        try {
          decoded = jwt.verify(req.params.token, config.keys.secret);
        } catch (error) {
          return response
            .status(401)
            .json({ error: 'Unauthorized..' });
        }
...

但是,代码可能会变得非常混乱,您可能希望以不同的方式拆分错误处理(例如:在某些 pre request 挂钩上进行 JWT 验证并只允许有效请求处理程序和/或在服务中执行findByIdsave部分,并且每次操作抛出一次)。

如果没有找到具有给定 ID 的实体,您可能需要抛出 404。

一次捕获所有内容

如果您想以 a)b)c) 的方式以 same 方式作出反应错了,那么第一个例子看起来就好了。

  a) var decoded = jwt.verify(req.params.token, config.keys.secret);
  b) var user = await models.user.findById(decoded.userId);
  user.active = true;
  c) await user.save();
  res.status(201).json({user, 'stuff': decoded.jti});

【讨论】:

    【解决方案2】:

    我阅读了一些文章,建议每个请求都需要一个 try/catch 块。这有什么道理吗?

    不,这不是必需的。 try/catchawait 在概念上与 try/catch 一起使用常规同步异常。如果您只想在一个地方处理所有错误,并希望您的所有代码都只中止到一个错误处理程序,无论错误发生在哪里,并且不需要捕获一个特定错误,因此您可以针对该特定错误做一些特殊的事情,那么你只需要一个try/catch

    但是,如果您需要专门处理一个特定错误,甚至可能允许其余代码继续执行,那么您可能需要一个更本地的错误处理程序,它可以是本地 try/catch.catch() on返回 Promise 的本地异步操作。

    或者如果我应该将它与第二个代码 sn-p 中的承诺混合使用。

    这个措辞表明您可能不太了解await 发生了什么,因为您的两个代码块都涉及承诺。

    在您的两个代码块中,models.user.findById(decoded.userId); 返回一个承诺。您可以通过两种方式使用该承诺。

    1. 您可以使用 await 来“暂停”函数的内部执行,直到该承诺解决或拒绝。

    2. 您可以使用.then().catch() 查看promise 何时解决或拒绝。

    两者都使用来自您的models.user.findById(decoded.userId); 函数调用的承诺返回。因此,您的措辞会更好地说“或者如果我应该在特定承诺上使用本地 .catch() 处理程序,而不是在一个地方捕获所有拒绝。


    这样做:

    // skip second async operation if there's an error in the first one
    async function someFunc() {
    
        try {
            let a = await someFunc():
            let b = await someFunc2(a);
            return b + something;
        } catch(e) {
            return "";
        }
    }
    

    类似于将你的承诺与最后一个 .catch() 处理程序链接起来:

    // skip second async operation if there's an error in the first one
    function someFunc() {
        return someFunc().then(someFunc2).catch(e => "");
    }
    

    无论哪个异步函数拒绝,都会应用相同的错误处理程序。如果第一个拒绝,则第二个不会执行,因为流程直接进入错误处理程序。如果在第一个异步操作中出现错误时,这就是您希望流程的运行方式,那么这非常好。

    但是,假设您希望将第一个函数中的错误转换为默认值,以便始终执行第二个异步操作。那么,这种控制流将无法实现这一点。相反,您必须在源头捕获第一个错误,以便您可以提供默认值并继续处理第二个异步操作:

    // always run second async operation, supply default value if error in the first
    async function someFunc() {
    
        let a;
        try {
            a = await someFunc():
        } catch(e) {
            a = myDefaultValue;
        }
        try {
            let b = await someFunc2(a);
            return b + something;
        } catch(e) {
            return "";
        }
    }
    

    类似于将你的 Promise 与一个 .catch() 处理程序链接到最后:

    // always run second async operation, supply default value if error in the first
    function someFunc() {
        return someFunc()
          .catch(err => myDefaultValue)
          .then(someFunc2)
          .catch(e => "");
    }
    

    注意:这是一个从不拒绝someFunc() 返回的承诺的示例,而是提供一个默认值(在此示例中为空字符串)而不是拒绝向您展示该函数中处理错误的不同方式。这当然不是必需的。在许多情况下,只返回被拒绝的 Promise 是正确的,然后调用者可以决定如何处理拒绝错误。

    【讨论】:

      猜你喜欢
      • 2018-04-13
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      • 2021-10-30
      • 2021-12-31
      • 1970-01-01
      • 2023-01-05
      • 1970-01-01
      相关资源
      最近更新 更多