Javascript “如何修复”';投掷';“本地捕获的异常”的定义;?

Javascript “如何修复”';投掷';“本地捕获的异常”的定义;?,javascript,node.js,rest,exception-handling,async-await,Javascript,Node.js,Rest,Exception Handling,Async Await,在这个处理RESTAPI调用的函数中,处理部分请求的任何被调用函数都可能抛出一个错误,以发出错误代码应作为响应发送的信号。但是,函数本身也可能发现错误,此时它应该跳转到异常处理块中 static async handleRequest(req) { try { let isAllowed = await checkIfIsAllowed(req); if (!isAllowed) { throw new ForbiddenExcep

在这个处理RESTAPI调用的函数中,处理部分请求的任何被调用函数都可能抛出一个错误,以发出错误代码应作为响应发送的信号。但是,函数本身也可能发现错误,此时它应该跳转到异常处理块中

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);
    }
}
Webstorm将在
抛出
下面加下划线,并显示以下消息:
“抛出”本地捕获的异常。此检查报告JavaScript throw语句的任何实例,其异常总是通过包含try语句捕获。使用throw语句作为“goto”来更改本地控制流可能会令人困惑。

然而,我不知道如何重构代码来改善这种情况

我可以将
catch
块中的代码复制粘贴到
if
检查中,但我相信这会降低我的代码的可读性和维护难度

我可以编写一个新函数,执行
isAllowed
检查,如果失败则抛出异常,但这似乎是在回避这个问题,而不是修复Webstorm应该报告的设计问题


我们是否以错误的方式使用异常,这就是我们遇到此问题的原因,还是Webstorm错误只是误导,应该禁用?

您正在检查某些内容,如果
被允许
失败,则抛出异常,但您知道在这种情况下该怎么做-调用
sendErrorCode
。如果您不知道如何处理这种情况,您应该向外部调用方抛出异常(即在异常情况下)

在这种情况下,如果发生这种情况,您已经有了一个确定的操作流程-只需直接使用它,而不必使用间接抛出/捕获:

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);
    }
}
我可以将
catch
块中的代码复制粘贴到
if
检查中,但我相信这会降低我的代码的可读性和维护难度


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

这可以给你一些提示,也许这就是原因(不确定是否相关)。

" try-catch块失败的原因是ajax请求是异步的。try-catch块将在ajax调用之前执行并发送请求本身,但在稍后返回结果时会抛出错误


执行try-catch块时,没有错误。抛出错误时,没有try-catch。如果您需要对ajax请求使用try-catch,请始终将ajax try-catch块放在成功回调内,而不是放在成功回调外。”

James Thorpe的回答在我看来有一个缺点。它不是干的,在这两种情况下,当您调用sendError时,您都会处理异常。让我们想象一下,我们有许多行代码,它们的逻辑类似于这样,可以在其中抛出异常。我觉得可以更好

这是我的解决方案

async function doSomethingOnAllowedRequest(req) {
    let isAllowed = await checkIfIsAllowed(req);
    if (!isAllowed) {
       throw new ForbiddenException("You're not allowed to do that.");
    }
    doSomething(req);
}
static async handleRequest(req) {
    try {
        let result = await doSomethingOnAllowedRequest(req);
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}

对于“为什么不使用异常作为正常的流控制?”这一问题有很好的答案

不抛出您将在本地捕获的异常的原因是您在本地知道如何处理这种情况,因此根据定义,它不是异常

@詹姆斯·索普的看起来不错,但@matchish觉得很干。我说,一般来说,情况并非如此。DRY的意思是“不要重复你自己”,是由那些创造这个短语的人定义的,“每一个知识都必须在一个系统中有一个单一的、明确的、权威的表示”。当应用于编写软件代码时,它是关于不重复复杂代码的

实际上,通过将重复的代码提取到函数中,然后从先前重复的位置调用该函数,任何被称为违反DRY的代码都被称为“修复”。有多个代码调用部分
sendErrorCode
是解决问题的方法。关于如何处理错误的所有知识都在一个确定的位置,即
sendErrorCode
函数

我想稍微修改一下@James Thorpe的回答,但这与其说是真正的批评,不如说是一种狡辩,即
sendErrorCode
应该接收异常对象或字符串,但不能同时接收这两个对象:

static async handleRequest(req) {
    try {
        let isAllowed = await checkIfIsAllowed(req);
        if (!isAllowed) {
            sendErrorCode(new ForbiddenException("You're not allowed to do that."));
            return;
        }
        let result = await doSomething(req); // can also raise exceptions
        sendResult(result);
    } catch(err) {
        sendErrorCode(err);
    }
}
更大的问题是发生错误的可能性有多大,处理
是否合适!作为例外,我被允许使用
。异常旨在处理异常或不可预测的情况。我希望
!我被允许是一个正常的事件,应该用特定于该情况的逻辑来处理,而不是,比如说,突然无法查询数据库,而该数据库有我被允许的问题的答案


@matchish将
DoSomethingoAllowedRequest
的契约从从不引发异常的契约更改为常规引发异常的契约,将异常处理的负担推到了所有调用方身上。这可能会导致多个调用者重复使用相同的错误处理代码,从而违反DRY,因此抽象地说,我不喜欢它。实际上,这取决于总体情况,例如有多少呼叫者,以及他们对错误的响应是否相同

因为这不是一个阻塞错误,而是一个IDE建议,所以应该从两个方面来看待这个问题

第一方面是表现。如果这是一个瓶颈,并且有可能将其用于编译或传输到nodejs的新版本(尚未发布),那么重复的存在并不总是一个坏的解决方案。在这种情况下,IDE似乎恰恰暗示了这一点,而且这样的设计在某些情况下可能导致糟糕的优化

第二方面是代码设计。如果它能使代码更具可读性,并简化其他开发人员的工作,请保留它。从这个角度来看,已经提出了解决方案
  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;
  }