完整的ppt来源于Node.js Best practices,作者Felix Geisendörfer,需翻越
Callbacks
下面是关于解析json文件的示例代码:
var fs = require('fs);
function readJSON(path, cb){
fs.readFile(path, 'utf8', function(err, data){
cb(JSON.parse(data));
}
}
显然,上面的代码没有处理异常情况,因此再加个异常处理逻辑上去:
var fs = require('fs);
function readJSON(path, cb){
fs.readFile(path, 'utf8', function(err, data){
if(err) return cb(err);
cb(JSON.parse(data));
}
}
还没有结束,我们还没考虑到文件内容不是json这种情况,会导致parse出现异常,因此再处理一下:
var fs = require('fs);
function readJSON(path, cb){
fs.readFile(path, 'utf8', function(err, data){
if(err) return cb(err);
try{
cb(JSON.parse(data));
}catch(err){
cb(err);
}
}
}
对于cb来说,仍然无法区分正常结果和异常内容,这个问题通常可以通过增加一个err参数来处理,如:
var fs = require('fs);
function readJSON(path, cb){
fs.readFile(path, 'utf8', function(err, data){
if(err) return cb(err);
try{
var json = JSON.parse(data);
}catch(err){
return cb(err);
}
cb(null, json);
}
}
这个示例告诉我们,对于callback,需要时刻准备应付正常结果和异常情况的处理。
再来看看另外一个常见错误:
function readJSONFiles(files, cb){
var results = {};
var remaining = files.length;
files.forEach(function(file){
readJSON(file, function(err, json){
if(err) return cb(err);
results[file] = json;
if(!--remaining) cb(null, results);
}
});
}
这里隐含了一个常见的场景:批量处理时,任意一个失败,及时退出。有时候可以用标识符,这里采用另外一种手法:重置回调方法。
function readJSONFiles(files, cb){
var results = {};
var remaining = files.length;
files.forEach(function(file){
readJSON(file, function(err, json){
if(err){
cb(err);
cb = function(){};
return;
}
results[file] = json;
if(!--remaining) cb(null, results);
}
});
}
Nested Callbacks
先看看一个恐怖的例子:
db.query('SELECT A ...', function(){
db.query('SELECT B ...', function(){
db.query('SELECT C ...', function(){
db.query('SELECT D ...', function(){
});
});
});
});
活生生就是一个怪物:),多层嵌套的回调不是很好的风格,我们需要一些流程控制的东西来辅助,例如Control Flow Libs:
var async = require('async');
async.series({
queryA: function(next){
db.query('SELECT A ...', next);
},
queryB: function(next){
db.query('SELECT B ...', next);
},
queryA: function(next){
db.query('SELECT C ...', next);
}
// ...
}, function(err, results){
//...
});
像上面的代码,最明显的地方就是异常处理被完全隔离出来。如果要把代码分布到很多小方法里边的话,Node.js的确不是很容易做到。
Exceptions
通常throw new Error(msg)可以让你的程序进行异常退出,并在控制台上输入错误信息和堆栈信息。
但有时候我们要考虑的是,一些未知的bug,例如下面一个有bug的示例:
function MyClass(){}
MyClass.prototype.myMethod = function(){
setTimeout(function(){
this.myOtherMethod();
}, 10);
}
MyClass.prototype.myOtherMethod = function(){};
(new MyClass).myMethod();
我们可以采用Global Catch的方式:
process.on('uncaughtException', function(err){
console.err('uncaught exception: ' + err.stack);
});
更好的处理方式是:进程挂了,认栽了,到更高层面上去处理。
process.on('uncaughtException', function(err){
// You could use node-airbake for this
sendErrorToLog(function(){
// Once the error was logged, kill the process
console.err(err.stack);
process.exit(1);
}
});
Deployment
比较初级的方式是采用node直接运行或在后台运行。老手可能会采用一个脚本来搞:
#! /bin/bash
while :
do
node server.js
echo "Server crashed!"
sleep 1
done
专家级采用的方式可能是(借助成熟的集成工具):
#!upstart
description "myapp"
author "felix"
start on(local-filesystems and net-device-up IFACE=eth0)
stop on shutdown
respawn # restart when job dies
respawn limit 5 60 # give up restart after 5 respawns in 60 seconds
script
exec sudo -u www-data /path/to/server.js >> /var/log/myapp.log 2>&1
end script
当然,还有些创新风格的(基于托管平台的):
$git push joyent master
$git push nodejitsu master
$git push heroku master
没有托管平台的话,借助成熟的工具应该是最好的选择,性价比高。