所有的模塊接口應(yīng)該遵循 優(yōu)先暴露錯誤 這一原則。如下代碼所示,
module.exports = function (dragonName, callback) {
// do some stuff here
var dragon = createDragon(dragonName);
// note, that the first parameter is the error
// which is null here
// but if an error occurs, then a new Error
// should be passed here
return callback(null, dragon);
}
為了更好的理解這一原則,下面我們給出一個反例,
// this example is **BROKEN**, we will fix it soon :)
var fs = require('fs');
function readJSON(filePath, callback) {
fs.readFile(filePath, function(err, data) {
callback(JSON.parse(data));
});
}
readJSON('./package.json', function (err, pkg) {
// do something
}
當(dāng)fs.readFile
在執(zhí)行拋出一個Error
時,方法readJSON
將不會按照代碼的期望運行下去了。
我們對齊進(jìn)行修正,代碼如下,
// this example is **STILL BROKEN**, we are fixing it!
function readJSON(path, callback) {
fs.readFile(filePath, function(err, data) {
// here we check, if an error happened
if (err) {
// yep, pass the error to the callback
// remember: error-first callbacks
callback(err);
}
// no error, pass a null and the JSON
callback(null, JSON.parse(data));
});
}
這里,我們fs.readFile
的回調(diào)中優(yōu)先檢查err
對象,根據(jù)err
的值進(jìn)行不同的處理。
上面的代碼仍然有一個問題,就是當(dāng)回調(diào)中檢查到err
對象不為空時,代碼運行完if
分支之后并不會停下,而是繼續(xù)運行下去。這是因為我們在相應(yīng)的地方添加返回,這可能將會帶來一些不可預(yù)料的異常。所以,一般來說,我們都會直接return
回調(diào)。
// this example is **STILL BROKEN**, we are fixing it!
function readJSON(path, callback) {
fs.readFile(path, function(err, data) {
if (err) {
return callback(err);
}
return callback(null, JSON.parse(data));
});
}
此處有坑出沒!當(dāng)JSON.parse
方法不能正確的把一個字符串解析成json對象時,它可能會拋出一個exception
。
因為JSON.parse
是一個同步方法,我們可以簡單的使用一個try-catch
語句塊將其包裝起來。如下所示,
// this example **WORKS**! :)
function readJSON(path, callback) {
fs.readFile(path, function(err, data) {
var parsedJson;
// Handle error
if (err) {
return callback(err);
}
// Parse JSON
try {
parsedJson = JSON.parse(data);
} catch (exception) {
return callback(exception);
}
// Everything is ok
return callback(null, parsedJson);
});
}
注意 永遠(yuǎn)不要給異步方法(異步回調(diào))添加try-catch
,因為要捕獲一個未來才會執(zhí)行到的函數(shù)所拋出的錯誤是不可能的。
this
以及new
在Node.js中嘗試綁定一個特定的上下文環(huán)境給運行環(huán)境不是好的主意,因為Node.js本身就是以使用回調(diào)函數(shù)及高階函數(shù)為一大特色。它推薦的編程風(fēng)格就是使用函數(shù)式的編程風(fēng)格和思想。
當(dāng)然,在有些場景下,使用基本原型、對象等編程手段將會更加有效率。但是如果可能的話,應(yīng)該盡量避免這種思路,使用Node.js推薦的風(fēng)格。
把問題分解成一個個簡單的小問題是一個好的思路(the unix-way)。
Developers should build a program out of simple parts connected by well defined interfaces, so problems are local, and parts of the program can be replaced in future versions to support new features.
始終應(yīng)該遵循這樣一個原則, 不要一個模塊包含過多的功能,應(yīng)該盡量保持簡單和功能單一化 。
建議使用已有的成熟的異步處理模塊來書寫代碼。
(譯者:這部分的內(nèi)容感覺好low,感覺沒有存在的意義。)
錯誤處理可以分為兩大類, 操作性錯誤(operational errors) 和 代碼錯誤(programmer errors) 。
操作性錯誤可能發(fā)生在一些書寫的很好的代碼中,因為它們并不是bug,而是一些由于系統(tǒng)或者網(wǎng)絡(luò)等原因?qū)е碌膯栴},比如,
下面是解決操作性錯誤的常規(guī)做法,
代碼錯誤就是程序bug!你可以通過如下幾種方式來避免它們,
undefined
上讀取一個屬性因為這些都是程序bug,將會導(dǎo)致你的程序直接崩潰,而且你還不知道何時何地將會導(dǎo)致你的程序潰崩。所以當(dāng)這類錯誤發(fā)生導(dǎo)致程序崩潰時,我們使用一個守護(hù)進(jìn)程重啟你的程序。比如,supervisord或者monit。
npm init
來開始一個新項目npm init
可以幫助你自動生成應(yīng)用的package.json
文件。它將某些字段設(shè)為默認(rèn)值,當(dāng)然你后面可以手動修改。
所以,當(dāng)你開始一個新項目時,應(yīng)該像下面這樣,
mkdir my-awesome-new-project
cd my-awesome-new-project
npm init
start
和test
腳本在你的package.json
中你可以在scripts
部分做一些腳本設(shè)置。npm init
命令會默認(rèn)生成start
和test
部分對npm start
和npm test
命令進(jìn)行支持。
此外,你還可以自定義可運行的腳本設(shè)置, npm run-script <SCRIPT_NAME>
。
無論是生產(chǎn)環(huán)節(jié)還是開發(fā)環(huán)境的部署都應(yīng)該帶有相應(yīng)的環(huán)境變量。一般性的做法是設(shè)置NODE_ENV
環(huán)境變量。
使用nconf模塊你可以根據(jù)不同的環(huán)境加載你自定義的環(huán)境配置。
當(dāng)然,你也可以使用內(nèi)置的process.env
對象來重置你的環(huán)境配置。
建議優(yōu)先使用已有的成熟的模塊或者解決方案。NPM上面有大量的模塊,總會找到你需要的模塊的。
使用統(tǒng)一的代碼風(fēng)格,無論你的代碼量多么的龐大,都是相對容易閱讀的。統(tǒng)一的代碼風(fēng)格一般包含, 縮進(jìn)規(guī)則 , 變量命名規(guī)則 等等。
這里有一份參考,RisingStack‘s Node.js Style Guide。
我希望這篇文章能夠讓你在Node.js的世界中少走一些彎路。
balabalabalabala…
更多建議: