NodeJS最佳實(shí)踐

2018-06-09 17:07 更新

代碼風(fēng)格

回調(diào)函數(shù)的相關(guān)約定

所有的模塊接口應(yīng)該遵循 優(yōu)先暴露錯(cuò)誤 這一原則。如下代碼所示,

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);
}

在回調(diào)函數(shù)中總是優(yōu)先檢查錯(cuò)誤

為了更好的理解這一原則,下面我們給出一個(gè)反例,


// 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í)行拋出一個(gè)Error時(shí),方法readJSON將不會(huì)按照代碼的期望運(yùn)行下去了。

我們對(duì)齊進(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對(duì)象,根據(jù)err的值進(jìn)行不同的處理。

回調(diào)函數(shù)中的return

上面的代碼仍然有一個(gè)問(wèn)題,就是當(dāng)回調(diào)中檢查到err對(duì)象不為空時(shí),代碼運(yùn)行完if分支之后并不會(huì)停下,而是繼續(xù)運(yùn)行下去。這是因?yàn)槲覀冊(cè)谙鄳?yīng)的地方添加返回,這可能將會(huì)帶來(lái)一些不可預(yù)料的異常。所以,一般來(lái)說(shuō),我們都會(huì)直接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));
    });
}

只能同步方法中使用try-catch語(yǔ)句

此處有坑出沒(méi)!當(dāng)JSON.parse方法不能正確的把一個(gè)字符串解析成json對(duì)象時(shí),它可能會(huì)拋出一個(gè)exception

因?yàn)?code>JSON.parse是一個(gè)同步方法,我們可以簡(jiǎn)單的使用一個(gè)try-catch語(yǔ)句塊將其包裝起來(lái)。如下所示,

// 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,因?yàn)橐东@一個(gè)未來(lái)才會(huì)執(zhí)行到的函數(shù)所拋出的錯(cuò)誤是不可能的。

盡量避免使用this以及new

在Node.js中嘗試綁定一個(gè)特定的上下文環(huán)境給運(yùn)行環(huán)境不是好的主意,因?yàn)镹ode.js本身就是以使用回調(diào)函數(shù)及高階函數(shù)為一大特色。它推薦的編程風(fēng)格就是使用函數(shù)式的編程風(fēng)格和思想。

當(dāng)然,在有些場(chǎng)景下,使用基本原型、對(duì)象等編程手段將會(huì)更加有效率。但是如果可能的話,應(yīng)該盡量避免這種思路,使用Node.js推薦的風(fēng)格。

模塊功能單一化

把問(wèn)題分解成一個(gè)個(gè)簡(jiǎn)單的小問(wèn)題是一個(gè)好的思路(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)該遵循這樣一個(gè)原則, 不要一個(gè)模塊包含過(guò)多的功能,應(yīng)該盡量保持簡(jiǎn)單和功能單一化 。

使用成熟的異步模塊

建議使用已有的成熟的異步處理模塊來(lái)書(shū)寫(xiě)代碼。

總是進(jìn)行錯(cuò)誤處理

(譯者:這部分的內(nèi)容感覺(jué)好low,感覺(jué)沒(méi)有存在的意義。)

錯(cuò)誤處理可以分為兩大類, 操作性錯(cuò)誤(operational errors)代碼錯(cuò)誤(programmer errors) 。

操作性錯(cuò)誤

操作性錯(cuò)誤可能發(fā)生在一些書(shū)寫(xiě)的很好的代碼中,因?yàn)樗鼈儾⒉皇莃ug,而是一些由于系統(tǒng)或者網(wǎng)絡(luò)等原因?qū)е碌膯?wèn)題,比如,

  • 請(qǐng)求超時(shí)
  • 內(nèi)存溢出
  • 鏈接遠(yuǎn)程服務(wù)器失敗

操作性錯(cuò)誤的處理

下面是解決操作性錯(cuò)誤的常規(guī)做法,

  • 嘗試解決導(dǎo)致錯(cuò)誤的客觀因素。如果文件丟失,那你應(yīng)該先創(chuàng)建一個(gè)文件。
  • 重復(fù)失敗的操作。當(dāng)網(wǎng)絡(luò)連接異常的時(shí)候,應(yīng)該多試幾次。
  • 告訴客戶端,有些東西還沒(méi)準(zhǔn)備好。
  • 重啟相關(guān)的服務(wù)。

代碼錯(cuò)誤

代碼錯(cuò)誤就是程序bug!你可以通過(guò)如下幾種方式來(lái)避免它們,

  • 調(diào)用一個(gè)不帶回調(diào)的異步方法(譯者:這里啥意思?沒(méi)懂!)
  • 不要試圖在undefined上讀取一個(gè)屬性

代碼錯(cuò)誤的處理

因?yàn)檫@些都是程序bug,將會(huì)導(dǎo)致你的程序直接崩潰,而且你還不知道何時(shí)何地將會(huì)導(dǎo)致你的程序潰崩。所以當(dāng)這類錯(cuò)誤發(fā)生導(dǎo)致程序崩潰時(shí),我們使用一個(gè)守護(hù)進(jìn)程重啟你的程序。比如,supervisord或者monit

工作流程

使用npm init來(lái)開(kāi)始一個(gè)新項(xiàng)目

npm init可以幫助你自動(dòng)生成應(yīng)用的package.json文件。它將某些字段設(shè)為默認(rèn)值,當(dāng)然你后面可以手動(dòng)修改。

所以,當(dāng)你開(kāi)始一個(gè)新項(xiàng)目時(shí),應(yīng)該像下面這樣,

mkdir my-awesome-new-project
cd my-awesome-new-project
npm init

提供starttest腳本

在你的package.json中你可以在scripts部分做一些腳本設(shè)置。npm init命令會(huì)默認(rèn)生成starttest部分對(duì)npm startnpm test命令進(jìn)行支持。

此外,你還可以自定義可運(yùn)行的腳本設(shè)置, npm run-script <SCRIPT_NAME>。

環(huán)境變量

無(wú)論是生產(chǎn)環(huán)節(jié)還是開(kāi)發(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對(duì)象來(lái)重置你的環(huán)境配置。

不要重復(fù)造輪子

建議優(yōu)先使用已有的成熟的模塊或者解決方案。NPM上面有大量的模塊,總會(huì)找到你需要的模塊的。

使用統(tǒng)一的代碼風(fēng)格

使用統(tǒng)一的代碼風(fēng)格,無(wú)論你的代碼量多么的龐大,都是相對(duì)容易閱讀的。統(tǒng)一的代碼風(fēng)格一般包含, 縮進(jìn)規(guī)則 , 變量命名規(guī)則 等等。

這里有一份參考,RisingStack‘s Node.js Style Guide。

接下來(lái)…

我希望這篇文章能夠讓你在Node.js的世界中少走一些彎路。

balabalabalabala…



以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)