如何在2016年成為一個更好的Node.js開發者

jopen 10年前發布 | 25K 次閱讀

Statement

使用ES2015

在2015年的夏天,ES2015的最終草案(即ES6)正式發布了。該版本為JavaScript語言增加了大量的新的語言特性,主要包括:

  • 箭頭函數
  • 模版字符串
  • rest operator(不定參數), argument spreading
  • 生成器
  • promises
  • maps, sets
  • symbols

以及很多其他特性。一個更加完整的新特性的列表你可以從Kyle SimpsonES6 and Beyond中進行了解。 并且它們中的絕大部分特性已經被加入到了Node.js v4中。

在客戶端,你也可以借助Babel來使用ES6的所有新特性,Babel是一個JavaScript轉譯器。目前在服務器端, 我們只傾向于使用那些被加入到最新的穩定版本的特性,這樣無需轉譯代碼,這可以避免出現那些令我們頭疼的潛在問題。

對于Node.js中的ES6的更多信息,你可以訪問官方站點:https://nodejs.org/en/docs/es6/

回調約定 - 同時支持Promise

在去年,我們可能會推薦你為你的模塊暴露錯誤優先的回調接口。但是隨著生成器函數的正式標準化,并且異步函數也即將到來, 因此我們現在建議你在編寫模塊的接口時應該暴露支持Promise的的錯誤優先的回調函數。

為什么需要這樣?首先回調接口是為了提供向后兼容性,為了能夠在未來能夠獲得更好的兼容性,需要同時提供Promise支持。

你可以參考下面的例子來進一步的理解具體應該如何進行編程。在這個例子中readPackage函數讀取了package.json文件, 并同時通過Promise和回調接口返回了它的內容。

const fs = require('fs'); function readPackage (callback) {   // as of now we do not have default values in Node.js   callback = callback || function () {}   return new Promise((resolve, reject) => {     fs.readFile('./package.json', (err, data) => {       if (err) {         reject(err);         return callback(err);       }       resolve(data);       return callback(null, data);     })   })  } module.exports.readPackage = readPackage; 

異步模式

在Node.js中,很長一段時間你只有兩種方法來管理異步流:回調或者流(Stream)。對于回調函數而言, 你可以使用類似于async這類庫, 對于流而言,有throughblhighland等庫可以選擇。

但是隨著Promise、生成器、異步函數等被逐漸引入進標準的ECMAScript,JS中的流程控制也得到了極大的改善。

關于異步JavaScript的發展歷史,你可以參考異步JavaScript的發展歷程這篇博文。

錯誤處理

錯誤處理在應用開發過程中起著至關重要的作用:確定應用崩潰的時間,或者僅僅是打印錯誤信息,確保應用繼續運行都是有一定難度的。

為了能夠更簡單的說明這個問題,我們決定將其分為兩種:程序員錯誤(programmer errors)和運算錯誤(operational errors)。

程序員錯誤就是我們所說的bug,由于你不知道程序運行的確切狀態因此當出現錯誤時你最好立刻停止應用的運行(crash the process)。

另一方面,運算錯誤是由于系統或者遠程服務本身所導致的問題。例如:請求超時和內存不足等。基于錯誤發生的特點,你可以對癥下藥, 然后重試,例如文件丟失,你可以去創建相應的文件。

在回調中進行錯誤處理

如果一個錯誤發生在異步操作的過程中,錯誤對象應該作為異步函數的第一個參數進行傳遞。你必須始終要檢查該錯誤對象并進行錯誤處理。

在前面的有關回調約定的例子里面已經展示了如何在回調函數中進行錯誤的優先處理。

在Promise中進行錯誤處理

如果是下面的代碼片段會發生什么情況?

Promise.resolve(() => 'John')   .then(() => {     throw new Error('ops');   })   .catch((ex) => {     console.log(ex);   })   .then(() => {     throw new Error('ups');     console.log(Doe');   }) 
  1. 在第3行會拋出一個異常。
  2. catch會處理它,并且在stdout中打印出:[Error: ops]
  3. 執行繼續,并且在第9行會拋出一個新的錯誤
  4. 沒有了

的確沒有什么了 - 最后一個被拋出的錯誤將會是靜默的。你需要注意,你應該始終以一個catch語句作為promise鏈的最后一環。 這會為你解決很多頭疼的問題。像下面這樣:

Promise.resolve(() => 'John')   .then(() => {     throw new Error('ops');   })   .catch((ex) => {     console.log(ex);   })   .then(() => {     throw new Error('ups');     console.log(Doe');   })   .catch((ex) => {     console.log(ex);   }); 

現在會輸出如下內容:

[Error: ops]
[Error: ops]

使用JavaScript標準風格

在過去幾年中,我們會使用JSHint、JSCS、ESLint等非常有用的代碼質量工具來盡可能的自動化檢查我們的代碼。

最近,當談到代碼風格的時候,我們使用ferossJavaScript標準風格

js standard code style

原因是它非常的簡單:無需任何配置文件,只需要將其放到項目中。主要包括如下一些規則:

  • 使用2個空格作為縮進
  • 字符串使用單引號 - 除了為了避免轉義
  • 不要包括沒有被使用的變量
  • 沒有分號
  • 永遠不要以 ( 或者 [ 作為一行的開始
  • 關鍵字后加空格 if (condition) { ... }
  • 函數名后加空格 function name (args) { ... }
  • 始終使用===代替==,但是可以使用obj == null來檢查null || undefined
  • 始終要處理Node.js的err函數參數
  • 始終要為瀏覽器全局變量增加window前綴,除了documentnavigator
  • 盡可能避免使用類似于openlengthevetname等走位瀏覽器全局變量。

當然,如果你的 編輯器只支持ESLint的話,這里有一個ESLint的規則庫用于使用標準風格,即eslint-plugin-standard。 安裝了這個插件后,你的.eslintrc文件可以是下面這樣的:

{
    "plugins": [
        "standard"
    ],
}

12-Factor應用(The Twelve-Factor Application)

如今,軟件通常會作為一種服務來交付,它們被稱為網絡應用程序,或軟件即服務(SaaS)。 12-Factor應用宣言描述了進行Web應用開發的最佳實踐:

  1. 基準代碼:一份基準代碼,多份部署
  2. 依賴:顯示聲明依賴
  3. 配置:在環境中存儲配置
  4. 后端服務:把后端服務當作附加資源
  5. 構建、發布、運行:嚴格分離構建和運行
  6. 進程:以一個或多個無狀態進程運行應用
  7. 端口綁定:通過端口綁定提供服務
  8. 并發:通過進程模型進行擴展
  9. 易處理:快速啟動和優雅終止可最大化健壯性
  10. 開發環境與線上環境等價:盡可能的保持開發、預發布、線上環境相同
  11. 日志:把日志當作事件流
  12. 管理進程:后端管理任務當作一次性進程運行

這套理論適用于任意語言和后端服務(數據庫、消息隊列、緩存等)開發的應用程序。

開始新的項目

始終通過npm init命令來開始一個新項目。這可以為你的項目創建一個初始的package.json

如果你想跳過初始的提問并直接使用默認的配置,只需要運行npm init --yes即可。

監控你的應用

當發生某個故障或是故障即將發生時,及時的通知你,能夠為你挽回損失。

為了進行應用的監控,你可以使用類似的SaaS產品或是開源軟件。在開源軟件方面,主要包括:Zabbix, Collected, ElasticSearchLogstash

如果你不想要自己進行部署,可以考慮使用線上的服務,你可以嘗試使用Trace, 它是我們公司開發的Node.js和微服務監控解決方法。

trace img

使用構建系統

盡可能的自動化一切東西。沒有什么比讓開發來做應該讓grunt做的事情更無聊和令人惱火的了,這不僅浪費時間,而且沒有意義。

現如今JvavaScript的這類工具已經非常的豐富了,包括Grunt, Gulp, 和Webpack,你知道幾個就行。

在RisingStack,絕大部分的前端開發新項目都是使用Webpack來進行自動化構建,其他類型的則使用gulp實現自動化任務。 對于新手而言,Webpack可能會花費大量的時間去理解,所以我強烈建議你去閱讀一下Webpack Cookbook

使用最新的長期支持(LTS)的Node版本

為了能夠更好的獲取穩定性和新特性,我們建議你使用最新的Node的LTS(長期支持)版本,它們是使用偶數發布編號的版本。 當然,你也可以自由的使用最新的實驗版本,即稱為穩定發布版本的使用奇數發布編號的。

如果你需要為多個項目工作,并且使用了不同的Node.js版本,建議你最好使用一個Node版本管理器——nvm

更多信息你可以參考Node.js官方網站的發布信息:

What You Should Know about Node.js v5 and More

每周更新你的項目依賴

養成每周更新一次你的項目依賴的習慣。這方面,你可以使用npm outdated或者是ncu包。

選擇合適的數據庫

當我們談到Node.js和數據庫的時候,可能你想到的第一個技術是MongoDB。當然這并沒有什么錯,但是你不應該直接就去使用它。 在這么做之前你需要問你自己和你的團隊幾個問題。包括下面幾個:

  • 應用會有結構化數據嗎?
  • 應用會進行交易處理嗎?
  • 數據需要存放多長時間?

可能你需要的僅僅是Redis,或者是如果你有結構化數據,那么你要用的可能是PostgrelSQL。 如果你需要在Node.js中使用SQL的話,你可以看看knex

使用語義版本控制(Semantic Versioning)

語義版本控制是一種為了兼容性空啊率的使用三段式版本號的正式約定,即:major.minor.patch,分別為主版本,次版本,補丁。

如果是一個不會向后兼容(backward-compatible)的API變化使用主版本號。當添加新的特性且API變化是向后兼容的時候使用次版本號。 如果只是對Bug進行修復可以使用包版本號。

幸運的是,你可以使用semantic-release這個模塊自動化你的JavaScript的模塊發布。

堅持閱讀

在JavaScript和Node.js世界,堅持保持對最新的新聞和技術進展的關注是件具有挑戰的事情。 為了能夠讓這件事變得簡單,確保你訂閱了如下幾個媒體: