Phoebe Li
Sept. 26
基本概念


主要思想:子程序应该不因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。更一般的说,其核心想法是要承认程序都会有问题,都需要被修改。
Anything that can go wrong will go wrong.
三种常见方法
举例来说,如果系统假定一份客户信息文件所含的记录数不能超过50000,那么程序中可以包含一个断定记录数小于等于50000的断言。只要记录数小于等于50000,这一断言就会默默无语,然而一旦记录数超过50000,它就会大声的“断言”说程序中存在一个错误。
断言是指在开发期间使用的、让程序在运行时进行自检的代码(通常是一个子程序或宏)。
public static void main(String[] args) {
int customerNum = 10000;
assert customerNum <= 50000 :
"customer number is more than 50000.";
}断言(Assert)模块用于为应用编写单元测试,可以通过require('assert')对该模块进行调用。
var assert= require('assert');
exports.index = function(req, res){
assert.equal('1', '2', ['1和2是不相等的']);
//assert.ifError(true);
res.render('index', { title: 'Express' });
};--word同时对一个条件使用断言和错误处理,以提高健壮性
处理错误最恰当的方式要根据出现错误的软件的类别而定。
应该在整个程序中采用一致的方式处理非法的参数,一旦确定了某种方法,就要确保始终如一地贯彻这一方法。
异常是把代码中的错误或异常事件传递给调用方代码的一种特殊手段。
在Node.js 中 通常我们使用的try/catch/final异常捕获语句,对于异步编程而言并不一定适用。try/catch操作只能捕获当次事件循环内的异常,对callback执行时抛出的异常将无能为力,node在处理异常上形成了一种约定,将异常作为回调函数的第一个实参传回,如果为空值,则表明异步调用没有异常抛出。
async(function (err, results) {
//TODO
});子程序使用throw抛出一个异常对象,再被调用链上层其他子程序的try-catch语句捕获
try {
...
} catch (ExceptionType1 name) {
...
} catch (ExceptionType2 name) {
...
} finally {
...
}注:finally 一定会执行,一般用来进行清理工作,如关闭流,关闭连接,释放或销毁资源
在异步方法的编写中,另一个容易犯的错误是对用户传递的回调函数进行异常捕获
try {
req.body = JSON.parse(buf, options.reviver);
callback();
} catch (err){
err.body = buf;
err.status = 400;
callback(err);
}try {
req.body = JSON.parse(buf, options.reviver);
} catch (err){
err.body = buf;
err.status = 400;
return callback(err);
}
callback();这段代码的意图是捕获JSON.parse()中可能出现的异常,但却错误的包含了用户传递的回调函数,若回调函数有异常,将导致回调函数执行两次,这可能导致业务混乱。
node.js在0.8版本发布时增加了domain模块,该模块提供一种方式用来将不同的IO操作归总到一个组中。如果任何注册的时间触发器或者回调函数触发了error事件或者throw了error对象,domain对象将会被通知到。
以上是官方的一个例子,很明显当匿名函数throw er后,将会被d.on('error',function(er){})捕获,并做处理。
var d = domain.create();
d.on('error', function(er) {
console.error('Caught error!', er);
});
d.run(function() {
process.nextTick(function() {
setTimeout(function() { // simulating some various async stuff
fs.open('non-existent file', 'r', function(er, fd) {
if (er) throw er;
// proceed...
});
}, 100);
});
});node.js的domain模块确实解决了很多重复代码的工作,在开发过程中建议将domain模块进行封装,单独写一个模块用来管理各种不同的错误处理,减少domain.create(),尽量使用1个或几个domain对象来处理整个应用的错误,便于管理

隔离程序: 使之包容由错误带来的损害,让程序的某些部分处理“不干净”的数据,某些部分处理“干净”的数据。
在隔离之外的假定所有数据都是不安全的,采用错误处理手段;在隔离之内的就假设数据都是安全的,使用断言来处理。
软件的好坏与其健壮性有很大的联系,所有的软件开发人员都要对它有足够的重视,从一点一滴开始做起,不要忽视任何的细节,不能盲目依赖测试去发现bug,而是以测试驱动编程,不断地思考可能发生的问题以进行预防,这才是防御式编程。