如何修复本地"异常"的"抛出"?

cib*_*cib 23 javascript rest exception-handling node.js async-await

在处理REST API调用的此函数中,处理部分请求的任何被调用函数都可能抛出错误,表示应将错误代码作为响应发送.但是,函数本身也可能发现错误,此时它应该跳转到异常处理块.

static async handleRequest(req) {
    try {
        let isAllowed = await checkIfIsAllowed(req);
        if (!isAllowed) {
            throw new ForbiddenException("You're not allowed to do that.");
        }
        let result = await doSomething(req); // can also raise exceptions
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}
Run Code Online (Sandbox Code Playgroud)

Webstorm将throw使用以下消息强调:'throw' of exception caught locally. This inspection reports any instances of JavaScript throw statements whose exceptions are always caught by containing try statements. Using throw statements as a "goto" to change the local flow of control is likely to be confusing.

但是,我不确定如何重构代码来改善这种情况.

我可以将catch块中的代码复制到if检查中,但我相信这会使我的代码不易读取并且难以维护.

我可以编写一个新函数来执行isAllowed检查,如果不成功则抛出异常,但这似乎是回避问题,而不是修复Webstorm据称报告的设计问题.

我们是否以错误的方式使用异常,这就是为什么我们遇到这个问题,或者Webstorm错误只是误导而应该被禁用?

J. *_*son 39

与 James Thorpe 的观点相反,我稍微更喜欢投掷的模式。我没有看到任何令人信服的理由来对待 try 块中的本地错误与从调用堆栈更深处冒出的错误有任何不同……只是抛出它们。在我看来,这是一致性的更好应用。

因为这种模式更加一致,所以当您想要将 try 块中的逻辑提取到可能位于另一个模块/文件中的另一个函数时,它自然更适合重构。

// main.js
try {
  if (!data) throw Error('missing data')
} catch (error) {
  handleError(error)
}

// Refactor...

// validate.js
function checkData(data) {
  if (!data) throw Error('missing data')
}

// main.js
try {
  checkData(data)
} catch (error) {
  handleError(error)
}
Run Code Online (Sandbox Code Playgroud)

如果不是在 try 块中处理错误,而是在 try 块之外对其进行重构,则逻辑必须更改。

此外,处理错误的缺点是让你记得提前返回,这样 try 块在遇到错误后不会继续执行逻辑。这很容易忘记。

try {
  if (!data) {
    handleError(error)
    return // if you forget this, you might execute code you didn't mean to. this isn't a problem with throw.
  }
  // more logic down here
} catch (error) {
  handleError(error)
}
Run Code Online (Sandbox Code Playgroud)

如果您担心哪种方法性能更好,那么您不应该担心。处理错误在技术上更高效,但两者之间的区别绝对微不足道。

考虑一下 WebStorm 在这里有点过于固执的可能性。ESLint 对此甚至没有规定。这两种模式都是完全有效的。

  • 我同意,但我相信这取决于具体情况。但对于以相同方式处理所有可能的错误的情况,我认为这会使代码更具可读性。 (4认同)
  • 同意。这只是那些没有任何区别的荒谬标准之一。 (3认同)
  • 此外,如果您有自己的自定义错误类,有时可以很好地抛出不同类型的错误,然后将它们全部捕获在一个位置,并根据它们的类型进行不同的处理。 (3认同)

Jam*_*rpe 26

如果isAllowed失败,你正在检查某些事情并抛出异常,但是你知道在那种情况下该怎么办 - 打电话sendErrorCode.如果你不知道如何处理这种情况,你应该向外部呼叫者抛出异常 - 即在特殊情况下.

在这种情况下,如果发生这种情况,您已经有了一个已定义的过程 - 只需直接使用它而不使用间接throw/catch:

static async handleRequest(req) {
    try {
        let isAllowed = await checkIfIsAllowed(req);
        if (!isAllowed) {
            sendErrorCode("You're not allowed to do that.");
            return;
        }
        let result = await doSomething(req); // can also raise exceptions
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以将catch块中的代码复制到if检查中,但我相信这会使我的代码不易读取并且难以维护.

相反,如上所述,我希望这是处理这种情况的方法.

  • “如果你不知道如何处理这种情况——即在特殊情况下,你应该向外部调用者抛出异常。” 如果这是真的,那就解释了这个问题。然而,这意味着我们在整个项目中错误地使用了异常,而不仅仅是这个函数。由于没有其他答案,我会接受这个。 (4认同)
  • 如果您所要做的就是“sendErrorCode()”然后返回,这很好。但是,如果您必须执行多项操作来处理或清除错误,那么您最终会重复代码。如果您的 try 块中有多个位置可以检测到内部错误,情况会变得更糟。如果无论是否出错都必须在 catch 块之后执行额外的工作,那么如果您在 try 块中返回,则无法到达那里。 (4认同)
  • @wojtow 你的场景听起来像是可以通过重构来处理...... (2认同)

Slo*_*man 12

既然这不是阻塞错误,而只是IDE建议,那么问题应该从两个方面来看。

第一面是性能。如果这是一个瓶颈,并且有可能将其用于编译或转移到新的(尚未发布的)nodejs 版本时,重复的存在并不总是一个糟糕的解决方案。在这种情况下,IDE 似乎准确地暗示了这种设计,并且在某些情况下,这种设计可能会导致优化不佳。

第二个方面是代码设计。如果它会使代码更具可读性并简化其他开发人员的工作 - 保留它。从这个角度来看,上面已经提出了解决方案。


Ayu*_*tha 7

在 try 块中返回一个 promise 拒绝而不是抛出错误

  try {
    const isAllowed = await checkIfIsAllowed(request);

    if (!isAllowed) {
      return Promise.reject(Error("You're not allowed to do that."));
    }

    const result = await doSomething(request);

    sendResult(result);
  } catch (error) {
    throw error;
  }
Run Code Online (Sandbox Code Playgroud)

  • 返回被拒绝的 Promise 是否比抛出错误更好? (5认同)
  • 请提供理由,解释为什么您的解决方案比其他解决方案更好。 (2认同)