JavaScript中是否可能使用try {}而没有catch {}?

188

我有几个函数,它们要么返回一些值,要么抛出错误。在主函数中,我调用了每一个函数,并希望返回每个函数返回的值,或者如果第一个函数抛出了错误,则继续执行第二个函数。

所以基本上我现在拥有的是:

function testAll() {
    try { return func1(); } catch(e) {}
    try { return func2(); } catch(e) {} // If func1 throws error, try func2
    try { return func3(); } catch(e) {} // If func2 throws error, try func3
}

但实际上我只想尝试返回它(即如果它不抛出错误)。我不需要catch块。然而,像try {}这样的代码会失败,因为缺少(未使用的)catch {}块。

我在jsFiddle上放了一个例子

所以,有没有办法在实现相同效果的同时删除那些catch块?

13个回答

328

如果一个 try 语句没有 catch 子句,它会将其错误传递给上一级的 catch 或者窗口(如果该 try 语句内没有定义 catch 子句)。

如果没有 catch 子句,try 表达式需要一个 finally 子句。

try {
    // whatever;
} finally {
    // always runs
}

1
那么最好的方法是编写类似于以下代码的内容:try { // 任何操作; } finally { try { // 任何操作; } finally { try { // 任何操作; } finally { try { // 任何操作; } finally { // 总是执行 }}}} - user2284570
3
上述评论没有准确回答原贴的问题,因为原贴作者不希望在函数1成功时运行函数2。 - Andrew Steitz
8
请注意,一个没有 catch 的 try 不会吞噬错误。 - Dan Dascalescu
谢谢,这正是我需要的 :-) 如果不使用try {}也可以工作,那就太棒了 我的意思是: async () => { indicateWorkInProgress() await pipelineStep1() await pipelineStep2() ... finally { stopIndicator() } } 很明显整个函数都是这样设计的; 那些 try 块太丑了... - Lenny

133
自从ES2019开始,可以有一个不带错误变量的空catch块。这被称为可选捕获绑定,并在V8 v6.6(于2018年6月发布)中实现。此功能自Node 10Chrome 66Firefox 58Opera 53Safari 11.1以来一直可用。
语法如下:

try {
  throw new Error("This won't show anything");
} catch { };

你仍然需要一个catch块,但它可以是空的,并且不需要传递任何变量。如果你根本不想要一个catch块,你可以使用try/finally,但请注意它不会像空的catch一样吞噬错误。

try {
  throw new Error("This WILL get logged");
} finally {
  console.log("This syntax does not swallow errors");
}


4
这个答案是最新的!在执行顺序上,1. 它尝试执行 try 块。2. 捕获错误。3. 执行 finally 块。4. 抛出错误。这正确吗? - helsont
感谢@helsont。至于第二个代码示例中的执行顺序,我不确定是否可以判断错误是否被捕获并重新抛出,或者只是(可能)简单地抛出而没有在第一次抛出时被捕获(因为没有catch)。用另一个try/catch将整个代码包围起来,您就能够捕获This WILL get logged错误。 - Dan Dascalescu

13

不是的,catch(或finally)是try的伙伴,并始终作为try/catch的一部分存在。

然而,像你的示例中那样将它们保留为空是完全有效的。

在你的示例代码注释中(如果func1抛出错误,则尝试func2),看起来你真正想做的是在前一个catch块内调用下一个函数。


1
你是正确的。然而,如果像 try {...}; try {...} 这样的代码是可能的,那么代码的含义可能会更清晰(尝试第一个,否则尝试第二个)。 - pimvdb
关于您的编辑:在JSFiddle示例中,第二个函数返回了一些内容,那么第三个函数在这种情况下真的被评估了吗?我认为return语句会停止其后的任何内容。 - pimvdb
1
@pimvdb 抱歉,我没有检查那个fiddle。return会导致函数过早返回。我会更新我的答案。 - alex
1
这个答案事实上是不正确的,你可以使用 try {}; finally {},如 https://dev59.com/HG025IYBdhLWcg3w1ZsL#5764505 所示。 - Daniel X Moore
1
@DanielXMoore 当然可以,但是finally{}基本上和catch{}的精神是一致的。我会更新答案。 - alex
如果 try { ... }; try { ... } 是合法语法,我非常确定它会/应该与 try { ... } finally { ... }; try { ... } finally { ... } 行为相同,这意味着异常不会被捕获。通常,您应该只捕获预期的异常(例如,“未找到理想移动”),以便“真正的”异常情况(例如,“x 不是函数”)不会被您的 try { ... } catch (e) { ... } 块默默吞噬。这就是为什么 Mozilla 具有非标准语法 try { ... } catch (e if e instanceof TypeError) { ... } 以及为什么 try 可以有无 catchfinally { ... } 的原因。 - binki

12

我不建议在没有catch语句的情况下使用try-finally,因为如果try块和finally块都抛出错误,那么在finally子句中抛出的错误会被向上传播,而try块的错误将被忽略。这是我的测试结果:

try {
  console.log('about to error, guys!');
  throw new Error('eat me!');
} finally {
  console.log ('finally, who cares');
  throw new Error('finally error');
}

结果:

>     about to error, guys!
>     finally, who cares
>     .../error.js:9
>         throw new Error('finally error');
>         ^
>     
>     Error: finally error

3
我认为你需要确保你的finally块足够简单,不会抛出任何异常。 - Konrad Gałęzowski

5

不,无法使用try块而不使用catch(或finally)。作为一种解决方案,我认为您可能希望定义一个类似于这样的辅助函数:

function tryIt(fn, ...args) {
    try {
        return fn(...args);
    } catch {}
}

然后像这样使用:

tryIt(function1, /* args if any */);
tryIt(function2, /* args if any */);

2
我决定从不同的角度来看待所提出的问题。
我已经找到一种方法,在部分解决另一个评论者列出的未处理错误对象的同时,允许紧密地遵循所请求的代码模式。
代码可以在http://jsfiddle.net/Abyssoft/RC7Nw/4/上看到。
try:catch被放置在一个for循环中,允许优雅地跌落。同时能够迭代所有需要的函数。当需要明确的错误处理时,使用额外的函数数组。如果出现错误并且具有错误处理程序元素的功能数组不是函数,则将错误转储到控制台。
根据stackoverflow的要求,在此将代码内联[编辑为JSLint兼容(删除前导空格以确认),提高可读性]。
function func1() {"use strict"; throw "I don't return anything"; }
function func2() {"use strict"; return 123; }
function func3() {"use strict"; throw "I don't return anything"; }

// ctr = Code to Run <array>, values = values <array>, 
// eh = error code can be blank.
// ctr and params should match 1 <-> 1
// Data validation not done here simple POC
function testAll(ctr, values, eh) {
    "use strict";
    var cb; // cb = code block counter
    for (cb in ctr) {
        if (ctr.hasOwnProperty(cb)) {
            try {
                return ctr[cb](values[cb]);
            } catch (e) {
                if (typeof eh[cb] === "function") {
                    eh[cb](e);
                } else {
                    //error intentionally/accidentially ignored
                    console.log(e);
                }
            }
        }
    }
    return false;
}

window.alert(testAll([func1, func2, func3], [], []));


2
"有没有办法在实现相同效果的同时删除这些catch块?"似乎是不行的,因为Javascript要求try块后面必须跟着catch或finally块。
尽管如此,还是有一种方法可以利用那些catch块来达到你想要的效果。
"//如果func1抛出错误,尝试func2",“if throws error”条件,就是catch块所用的地方。
既然它们的使用正是你想要的,为什么要删除呢?"
try { return func1(); }
catch {
   // if func1 throws error
   try { return func2(); } 
   catch {
      // if func2 throws error
      try { return func3(); } 
      catch {
         // if func3 throws error
      }
   }
}

我完全理解为什么您可能不需要一个 catch 块,并且会发现完全省略它更加清晰。但是我认为这不是那种情况。


1
刚刚注意到这已经快十年了...可能不值得写一个答案。 - Air
2
这对我很有帮助。谢谢你。 - user

2
如果您只想在出现错误时触发功能2和3,为什么不将它们放在catch块中?
function testAll() {
  try {
    return func1();
  } catch(e) {
    try {
      return func2();
    } catch(e) {
      try {
        return func3();
      } catch(e) {
        // LOG EVERYTHING FAILED
      }
    }
  }
}

0
另一种在JS中标记空代码块的方法是使用:/* empty */。 我的意思是:
try {
    // your code here
} catch { /* empty */ }

-1

它们在我所知道的每种具有它们的语言中都是一起使用的(JavaScript、Java、C#、C++)。不要这样做。


1
不可思议的是,我的回答五年后被踩了,尽管它和其他答案说的一样。只有我的回答似乎被踩了。版主们,请注意。 - duffymo
Tcl有一个非常方便的单词结构catch {my code} - MKaama
从ES2019开始,catch绑定是可选的。 - Dan Dascalescu
为什么?感觉没用,除非是try/finally。 - duffymo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接