NodeJS 最佳實踐

段昕理發表於2015-12-11

本文是“NodeJS 最佳實踐”教程,分上下兩個部分。

上篇

人們總是問我們關於Node.js的最佳實戰和技巧,所以打算通過這篇文章解釋清楚,並總結一下我們在RisingStack公司寫程式碼的經驗。

Node.js最佳實戰中的一部分是編碼規範,另一部分則是處理開發流程。

編碼規範

回撥慣例

模組應該公開一個錯誤優先(error-first)的回撥介面。

就像下面這樣:

確保在回撥中檢查錯誤資訊

要更好地弄明白為什麼必須這樣做,先想辦法建立一個會掛掉的例子,然後修復它。

首要問題是 readJSON函式,在執行過程中出現了錯誤,而這個函式卻沒有做任何錯誤檢查。你務必要先做錯誤檢查。

改進方案:

將回撥函式返回

上面的例子還是存在一個錯誤,就是如果錯誤發生了,if  中的表示式不會停止執行,而是繼續執行下去。這會導致很多未知的錯誤。長話短說,務必通過回撥函式返回。

僅在同步程式碼中使用try-catch

幾乎完美了!但還有一件事,我們必須要小心 JSON.parse。呼叫JSON.parse 時,如果傳入的字串無法解析成JSON格式,會丟擲異常。

由於JSON.parse是同步發生的,我們可以用try-catch包裝起來。請注意,你只能對同步程式碼塊做此操作,對回撥函式是不起作用的。

儘量避免 this 和 new 關鍵字

由於Node涉及了大量的回撥操作,並且重度使用高階函式控制流程,因此在Node中繫結一個具體的上下文並不總是行之有效。使用函數語言程式設計風格能避免不少麻煩。

當然,在某些情況下原型(prototype)可能更高效,不過只要可能,還是儘量避免它們。

建立微模組

用unix的方式:

開發者構建一個程式時應該將其分成很多簡單的模組,各部分由定義良好的介面整合,所以問題是區域性的,並且能通過替換程式部件的方式在將來的版中加入新特性。

不要建立怪獸般的程式碼,保持簡潔,一個模組就只做一件事,但是要做到極致。

使用良好的非同步模式

使用async非同步處理模組。

錯誤處理

錯誤可以分為兩部分,操作錯誤程式設計錯誤

操作錯誤

精心編寫的應用程式中也一樣會出現操作錯誤。因為這些不是 bug ,而是由於作業系統或遠端服務導致的,例如:

  • 請求超時
  • 系統記憶體不足
  • 遠端連線失敗

處理操作錯誤

根據不同執行錯誤的型別,你可以採用下面的方式處理:

  • 嘗試解決錯誤——如果檔案丟失,你可以提前建立一個。
  • 當處理網路通訊時,可以重試操作。
  • 把問題告訴客戶,表示有些功能不能正常工作——可以用於處理使用者輸入。
  • 如果錯誤無法在當前條件下解決,終止程式,例如應用程式無法讀取它的配置檔案。

還有,上述的所有處理方式都應該記錄日誌。

程式設計錯誤

程式設計錯誤都算是bug。下面所列的幾條你應該避免,例如:

  • 呼叫非同步函式時沒有回撥。
  • 不能讀取未定義(undefined)的屬性

處理程式設計錯誤

如果錯誤屬於bug,立刻終止程式,你並不知道應用當前的執行狀態。當錯誤發生時,程式控制系統應該會重啟應用程式,例如:supervisord 或者 monit

工作流技巧

使用 npm init 建立新專案

init 命令可以幫助你建立應用程式的 package.json 配置檔案。檔案設定了一些預設配置,之後可以修改。

建立一個優秀的專案應該這樣開始:

指定開始和測試指令碼。

在你的 package.son 檔案中,你可以在 scripts 部分中設定指令碼。npm init  預設會建立兩個,start 和 test 指令碼。可以通過 npm start 和 npm test 命令執行。

還有,作為加分項:你可以在這裡加入自定義指令碼,通過 npm run-script <SCRIPT_NAME> 來執行。

注意,NPM 會通過設定 $PATH 來掃描 node_modules/.bin 下的所有可執行指令碼。這樣可以避免安裝全域性的 NPM 模組。

環境變數

生產部署和演示部署都應該由環境變數來實現。最主流的實現方式是同時在生產和演示中設定 NODE_ENV變數。

根據你設定的環境變數,你可以使用 nconf 模組來載入配置資訊。

當然,你也可以在你的Node.js 應用中使用其它環境變數設定 process.env,這是一個包含了使用者環境的物件。

不要重新發明輪子

務必優先尋找現成的解決方案。NPM 的庫超級多,涵蓋了你平時需要的大部分功能。

使用風格指南

所有的程式碼都保持統一風格有助於理解大型程式碼庫。其中應該包含縮排、變數命名、最佳實踐以及其他方面。

如果想看一個實際的例子,請檢視  RisingStack 編寫的 Node.js 風格指南

後記

我希望這篇文章對你編寫Node.js有所幫助,並且解決一些令你頭疼的難題。下篇文章會繼續探討操作技巧和最佳實踐。

你可以從 持續部署Node.js 應用 閱讀部署相關的技巧。
還有,我們將於 11月21日舉辦名為  One-Shot Budapest 的 Node大會(NodeConf)。關注PayPal、NPM、Strongloop分享的經驗。希望到時能看到你。

下篇

你應該還記得我們上篇的Node.js 最佳實踐。這篇文章裡我們繼續討論更多的最佳實踐,這些實踐有助於你成為更棒的Node.js開發者

保持風格一致

當在一個較大的團隊裡開發JavaScript 應用程式時,建立一個所有人都遵守的風格指南非常重要。如果你想找靈感,我會推薦你去閱讀 RisingStack 的 Node.js 風格指南

但是這只是起步——當你設定好標準,所有團隊成員都必須遵守風格指南。這是 JSCS 誕生的原因。

JSCS 是一個JavaScript 編碼風格檢查工具。將JSCS加入專案對你來說小菜一碟:

你需要做的下一步關鍵就是在 package.json 檔案中加入下面的程式碼來開啟它:

當然,你也可以加入多個檔案、目錄檢查。但為什麼我們僅僅在 package.json 檔案中建立了一個自定義的指令碼呢?我們是以本地的方式安裝 jscs 的,所以在一個系統中可以有多個不同版本。這樣還能正常工作是因為NPM 執行時會將 node_modules/.bin  設定到 PATH上。

你可以在 .jscsrc 檔案中定義驗證規則,或者使用預設規則。從這裡可以檢視可用的預設,通過 --preset=[PRESET_NAME]來應用。

執行 JSHint、JSCS 規則

你的構建過程還應該包含 JSHint 和 JSCS,不過在開發者的電腦上執行 pre-commit checks 或許是個不錯的主意。

要實現這個很簡單,你可以使用 pre-commit NPM 庫:

然後在 package.json 檔案中作如下配置:

注意,pre-commit 將會掃描 package.json中script裡的所有指令碼。開啟以後,每次提交時都會自動進行檢查。

用JS替換JSON做配置

我們看到大量的專案都是使用JSON檔案做配置的。這是目前最普遍的做法,JS配置檔案則能夠提供更大的靈活度。所以我們推薦你使用 config.js 檔案:

使用 NODE_PATH

你是否曾經碰到過下面這種情況?

當你的專案結構變得錯綜複雜,模組依賴會非常麻煩。要解決這個問題有兩個辦法:

  • 把你的模組軟連結到node_modules目錄下。
  • 使用 NODE_PATH。

在RisingStack我們使用 NODE_PATH的方式,因為將所有相關檔案軟連結到 node_modules目錄需要大量額外的工作,並且在很多作業系統下都不適用。

設定 NODE_PATH

假設你的專案結構是這樣的:

0EA2EA61-DF4B-466F-9AFB-4EC56C5CA161

我們可以使用 指向 lib 目錄的NODE_PATH,而不是使用相對路徑。在我們的package.json 的 start script部分,我們使用NODE_PATH設定並且用npm start 執行專案。

依賴注入

依賴注入是一種軟體設計模式,是指將一到多個依賴(或服務)注入或通過引用的方式引入到需要依賴的物件。 

依賴注入在測試中非常有用。使用這個模式你可以輕鬆模擬模組間的依賴關係。

上面的例子中我們有兩個不通過的 db。在 index.js 檔案中是“真實的” db 模組,而第二段程式碼中我們只是簡單地建立了一個模擬的db模組。

這樣我們在測試時就可以輕鬆地將模擬的依賴引入模組。

開發應用時需要一臂之力?

RisingStack 提供了 JavaScript 開發和諮詢服務——如果你需要幫助請聯絡我們!