错误处理

(B) 流控制与值

两种语言把错误信息当做正则值(regular value)传递。另外两者都是用流控制结构:Javascript使用 throw catch finally ,Go使用 panic recover defer

(D) 使用方式

经管上面的声明是相似的,这两种语言在错误处理的方式和都不太一样。

JS

在JS中,抛出错误的方式取决于函数的同步或异步性质。 如果函数是同步的,那么错误发生时可以使用 throw,调用者可以用 try/catch来捕获它。

另外,异步函数需要通过回调函数的第一个参数来传递错误信息,或者返回一个 'rejected' Promise.

需要注意 async/await 机制(草案中),它可以通过try/catch捕获异步函数的错误,从而使同步或异步函数都能被try/catch捕获处理。

Go

在Go中,抛出错误的方式取决于整个应用的上下文中的严重程度。

例如,对于一个Web服务器应用,如果错误发生在请求处理的代码路径中,它不应该导致整个服务挂掉。 因此,这些错误应该当做最后参数返回给调用者。

另外,如果错误发生在应用初始化阶段,毫无疑问,程序不需要再继续运行下去了,所以这里应该使用 panic

(S) 跟踪堆栈的丢失

当把错误当做一个值来传递时,这里有个缺点,就是丢失了跟踪堆栈。这俩种语言都有此问题。这里有一些运行时的扩展库来帮助解决这个问题. 比如下面的库:

(D) 前景

Go的错误处理问题是讨论的热点。批评人士指出经常出现"nil handling"的错误处理代码。通常看起来像下面的代码:

if err != nil {
  return nil, err
}

一些人甚至踢出应该把上面的代码块制作成一个键盘按键,因为它使用的次数太多了。

这些评论也来自Go的用户。2018年有个用户调查 展示出有5%的回答者将"错误处理"标记在 "当下使用Go语言面临最大的挑战是什么?"问题的下面。

Go团队已经回复了此问题,并且在Go 2.0 中,改善错误处理是其目标之一。错误处理改善提升之路注定是崎岖的。try的提议在一个公开讨论里被拒绝了,这表现出很多社区对提出的补丁并不是很满意。更多的细节请看summary

我们可能需要到将来才能看到Go的错误处理到底变成了什么样子。