我曾经在我的JS类的任何方法中放置try...catch
:
var MyConstructor = function() {
this.init = function() {
try {
// the method code...
} catch(error) {
// the error manager log actions
}
};
// other methods, with the same try/catch usage
};
这样,保持代码接口相对简单,我认为我的代码中的任何错误都会被捕获并记录/管理。
var myInstance = new MyConstructor();
相反,每个脚本是否足够一个全局catch块? 关注每个可能(或值得注意的)错误,我觉得足以知道应用程序中发生的每个错误:
// no try...catch inside the classes, but only a global try...catch per script:
try {
var myInstance = new MyConstructor();
} catch(error) {
/*
log in the needed environment
(e.g. client-side, via console, or to the server...)
*/
}
我在Stackoverflow上搜索和读取线程以及关于JavaScript错误管理的非凡资源
在这个阶段,我感兴趣的是找到找到所有错误的最佳方法,而不是管理它们以获得用户界面的优雅行为。
这不是正确的方法吗?我对任何建议持开放态度。
答案 0 :(得分:2)
经验法则是你应该问自己“谁应该在逻辑上处理这个问题?”坚持下去。
重要的是要记住,当你编写一段代码时,你实际上写了一份合同,描述代码的各个部分是如何交互的。例如,在您创建MyConstructor实例的情况下,为什么会失败?它产生了什么样的承诺?最重要的是,谁应该处理它失败?
一些例子
我们假设我们有一个班级Car
,Car
的实例有一个方法drive(x)
。
当您致电drive(x)
时,Car
将x
位置移到右侧。
操作drive(x)
可能会失败,例如Car
已经位于屏幕边缘,或者Car
没有燃料。
我们刚刚将drive
定义为“汽车向右移动x个位置”,这意味着汽车期望能够完成驱动器操作并且无法完成它是逻辑上是一个例外。在这种情况下,很明显,处理异常的是驱动器的调用者而不是汽车本身,因为它不必知道它正在驱动的环境。更好的是,来电者不应试图将车开出边缘或没有任何燃料。
在另一个案例中
让我们说在同一个例子中Environment
是一个包含汽车的类,它有一个moveCars()
方法,根据一些内部包含的逻辑移动环境中的所有汽车。 Environment
由程序使用,期望它包含所有移动逻辑。我们在moveCars()
中使用了一些算法来保证汽车不会碰撞。
我们可能有一些我们在moveCars()
方法中没有想到的边缘情况,或者由于某些假设而不应该发生的情况,但环境用户希望它包含所有的移动逻辑表示发生异常时应自行处理。
那么,一般策略是什么?
您应该根据运行代码的组件的责任来处理异常。
答案 1 :(得分:1)
这个问题实际上不仅限于JavaScript。异常捕获的正确粒度取决于可能具有异常的模块和函数的正确粒度。精心设计的模块或功能应该与明确定义的合同(DbC)绑定。只要明确建立合同,异常处理问题就会变得容易得多。
关于合同的三个重要问题是:合同期望什么?合同保证什么?合同维持什么?例如,假设函数divide(a, b)
返回a / b
。此函数期望b
非零(precondition),如果b恰好为零,则此函数应抛出异常而不是 catch 异常。因为调用者有责任保证传递参数的有效性,这是合同的一部分。除此之外,divide
函数中可能发生的所有其他错误应该被捕获,因为这是它自己的责任。作为合同的另一部分,divide
承诺返回一个值(即商)乘以b
应等于a
(称为{{ 3}})。
异常处理可能很复杂。函数(或模块)可以选择捕获异常,如果它在其职责范围内,或者选择不捕获超出其职责的异常,或者选择先捕获异常,处理异常,然后在包装异常后重新抛出调用者作为调用者层的例外。
总而言之,异常处理不是一个独立的问题,它是整个系统设计的一部分。一旦设计师合理地将复杂系统分成相对简单的模块,每个模块都具有良好的抽象/接口和明确定义的合同/责任,处理异常的方式和位置应该是不言自明的。