天天看點

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

OSC 協作翻譯

英文原文:10 Node.js Best Practices: Enlightenment from the Node Gurus

編譯:邊城, BigEcho, Tocy, 無若, 火星撞地球的魔術師, ismdeep

我曾經在10 個技巧,2017 年成為更好的 Node 開發者介紹了10個Node.js的技巧和技術。這篇文章評述的内容是在那基礎之上進一步延伸出來的10個最佳實踐,幫助你将Node技能提高到新的層次。下面是本文涵蓋的内容:

1.使用npm腳本——停止使用bash腳本,npm腳本和Node能更好地組織腳本。比如,npm run build、start和test。當開發者考慮新項目的時候,npm腳本似乎是唯一值得相信的東西。

2.使用env變量——利用process.env.NODE_ENV,它可以設定為development或者production。某些架構也會使用這個變量,是以請按慣例使用它。

3.了解事件循環——setImmediate()并非立即執行,nextTick()也不一定就是下一個。使用setImmediate()或者setTimeout()會将CPU密集型任務放在下一個事件循環周期進行。

4.使用功能繼承——在調試代碼以及了解原型繼承或類的時候,要避免使用過多腦力陷入盲目的思想鬥争。像偉大的Node貢獻者們那樣使用功能繼承就好。

5.使用恰當的名稱——給文章起個有意義的名稱。同時請不要大寫檔案名,并在需要的時候添加連字元。大寫的文本名不會讓人覺得奇怪,但可能在跨平台時發生問題。

6.考慮不使用JavaScript——可憐的ES6/7經過6年的會議商讨終于誕生的時候,我們已經有更好的 JavaScript,CoffeScript。如果你願意高效産出代碼,并且不想再糾結var/const/let、分号、class和其它主題,那就用CoffeeScript。

7.提供原生代碼——在使用轉譯器的項目中,直接送出原生代碼(建構結果)可以讓你的項目不需要 建構直接運作。

8.使用gzip——唔!npm i compression -S和理性的日志——不要太多也不要太依賴環境。npm i morgan -S。

9.擴大規模——從使用Node進行開發的第一天開始就應該考慮叢集和無狀态服務。使用pm2或者strongloop的叢集控制。

10.緩存請求——從你的Node服務榨取最大性能,把它們放在像 Nginx 這樣的靜态檔案伺服器後面,并像 Varnish Cache 和 DNS 那樣對請求進行緩存。

下面我們依次來看看上面提到的每一條。

使用 NPM 腳本

現在npm腳本幾乎已經成為一個标準,它被用來進行建構、測試以及最重要的啟動應用。這是一個Node開發者遇到一個新Node項目的時候首先要看的地方。有些人(1, 2, 3, 4)甚至已經抛棄了Grunt、Gulp,轉用更低級更可依賴的npm腳本。我完全能夠了解他們的觀點。考慮到npm腳本有前後鈎子,你可以使它實作非常複雜的自動化:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

通常在進行前端開發的時候,你可能會運作兩個或者更多的監控程序以實時重新建構代碼。比如,一個 webpack程序,一個nodemon程序。因為第一個指令不會産生提示,你可以用&&來運作它們。不過有一個友善的子產品,叫做concurrently,它能同時啟動多個程序。

同時,應該在項目内安裝指令行的開發工具,比如 webpack、nodemon、gulp、Mocha等,以避免産生 沖突。你可以在bash/zsh的profile中指定像./node_modules/.bin/mocha這樣的路徑(PATH!):

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

使用環境變量

在一個項目的早期階段,利用環境變量,可以確定不洩露敏感資訊,并且能從一開始就正确建構代碼。而且,很多庫和架構(我知道其确切的表達)會将資訊放在 NODE_ENV 這樣的環境變量中修改。把它設定成 production。并把它設定你要的 MONGO_URI 和 API_KEY 的值。你可以建立一個 shell 檔案(例如:start.sh),并且添加到 .gitignore:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

Nodemon 也有一個配置檔案,你可以設定你自己的環境變量(例子):

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

了解事件循環

強大而聰明的事件循環之是以能讓Node如此快速和高效是因為它充分利用原本浪費在等待輸入和輸出任務的所有的時間。 是以,Node非常适合于優化I/O密集型系統。

如果你需要執行某些CPU密集型(例如,計算、密碼的哈希碼或者資料壓縮),那麼除了為這些CPU任務啟動新的程序之外,你可能想要探索如何使用setImmediate()或者setTimeout()來延期執行任務——它們回調函數中的代碼将在下一個事件循環周期繼續運作。 注意喽!nextTick()工作在同一個周期,與字面含義相反。

這是一幅來自工作于事件循環上的Bert Belder的圖。它非常清楚的展示了事件循環是如何工作的!

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

使用功能性繼承

JavaScript支援原型繼承,即某些對象從其它對象繼承。ES6中也加入了 class 運算符。不過它明顯比功能繼承更複雜。多數Node大量指出後者更為簡潔。它通過一個簡單的函數工廠模式實作,不需要使用原型、new或者this。當你更新原型的時候不會産生副作用(即導緻所有執行個體改變)因為在功能性繼承中每個對象自己有方法拷貝。

看看下面來自 TJ Holowaychuk 的代碼。TJ Holowaychuk 是一個天才,作品有 Express、Mocha、Connect、Superagent以及 其它很多Node子產品。Express就使用功能性繼承 (完整源代碼):

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

客觀的說,核心Node子產品使用了很多原型繼承。如果你也使用這種模式,一定要搞清楚它如何運作。你可以看看這裡的 JavaScript 繼承模式。

使用恰當的名稱

這一點是顯而易見的。好的名字具有文檔的作用。你更喜歡哪一個?

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

如果隻看 app.use(),我不知道 dexter 在幹啥。如果使用更有意義的名稱會怎麼樣:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

同樣的,檔案名也必須正确地反映其内部的代碼是做什麼用的。看看Node的lib目錄(GitHub 連結),這裡所有代碼都與平台綁定,你會看到清楚明白的檔案/子產品名稱(即使你對所有子產品都不熟悉):

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

内部子產品與代碼中的方法和變量一樣,使用下劃線标記(_debugger.js、_http_agent.js、_http_client.js)。這會讓開發者警覺:這是一個内部接口,如果你想使用它就得全靠自己——不要因為它被重構甚至被删除而産生抱怨。

考慮不要使用JavaScript

嗯?你剛剛讀對了嗎?但是究竟是什麼意思呢?是的。這是正确的。即使使用ES6和ES2016/ES7增加的兩個功能,JavaScript仍然有它的quirk。除了JavaScript,還有很多其他可供您或您的團隊通過極少設定中獲益的選擇。根據你的專業水準和應用程式的性質,你可能會選擇更好的TypeScript或Flow提供強大列印功能。另一種極端情況,也存在像Elm和ClojureScript這種純虛函數式語言。 CoffeeScript 是另一個偉大的和富有争議的測試選擇。你也可以了解下Dart 2.0。

當你需要的僅僅是幾個宏的話(宏允許使用建構你需要的語言),而不是一個完整的新語言,那麼可考慮下Sweet.js,它幾乎是這麼做的 - 允許你編寫用于生成代碼的代碼。

如果你選了非JavaScript路徑,請依然包含你所編譯的代碼,因為一些開發人員可能不太了解你所使用的語言并正确地建構它。例如,VS Code是最大的TypeScript項目之一,也許在Angular 2之後,Code開始使用TypeScript來對Node的核心子產品進行類型化。在VS Code repo(連結)的vscode/src/vs/base/node/中,你可以看到熟悉的子產品名稱,例如crypto、process等,但是都包含ts擴充名。在repo中還有其他ts字尾的檔案。但是,他們還包括使用原生JavaScript代碼的vscode/build。

了解 Express 中間件

Express 是個偉大而且成熟的架構。它的光彩來自允許大量其它子產品對其行為進行配置。這樣說來,你需要知道常用的中件間以及如何使用它。為什麼不看看我的 Express 作弊表。其中列有我一個主要的中間件。比如,npm i compression -S 會因為減少反應而降低下載下傳速度。logger('tiny')或logger('common')分别會提供更少(dev)或更多(prod)日志。

擴大規模

Node因為其非阻塞式I/O而在異步方面非常偉大,它隻需要簡間的代碼就能保持異步特性,因為就隻有一個線程。這使得有機會早期,甚至在寫第一行代碼的時候,就開始擴大規模。Node 有核心 cluster 子產品,它 讓你在縱向擴充時不會遇到太多問題。不過,使用像 pm2 或者 StrongLoop 的 叢集控制 這樣的工具可能是更好的方法。

例如,下面示範如何使用 pm2:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

然後你可以對同一個服務啟動 4 個執行個體:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

對于 Docker,pm2 版本2+ 提供了 pm2-docker。是以 Dockerfile 可以這樣:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

官方的 Alpine Linux pm2 映像在 Docker Hub。

緩存請求

這是一條DevOps最佳實踐,它允許你從Node執行個體中獲得更多的幫助資訊(你可以通過pm2或其他類似的獲得更多,見上文)。方法是讓Node伺服器做app類似的請求、處理資料和執行業務邏輯,并将流量負載到另一個Web伺服器(如Apache httpd或Nginx)的靜态檔案上。 再次,你可能使用Docker進行配置:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

我喜歡使用Docker組合來配置多個容器(nginx、Node、Redis、MongoDB)。示例如下:

10 個 Node.js 最佳實踐:來自 Node 大神的智慧之光

總結

在如今這個開源軟體的時代,你沒有借口不去學習那些已經開源并且可信的、測試過的源碼。你不必在自己的圈子裡得到這些(源碼)。學無止境,并且我堅信很快我們就從我們将要經曆的失敗和成功中獲得不同的且最好的練習。這是可以保證的。

最後我想寫一寫關于軟體正在如何吞并這個世界以及JavaScript正在如何吞并軟體的...它們和每年出現的标準一樣的版本,數不勝數的npm模型,工具和會議...但是相反隻要是我提過一句的我還是會完成的。

我發現好多人都在追趕下一代的新架構或者語言。這是典型的新鮮對象綜合症。他們每周學習新的庫以及每個月學習新的架構。他們強迫自己依賴Twitter、Reddit、Hacker News和JS Weekly。他們在JavaScript的世界裡頻繁使用這些來拖延(自己創造自己的東西)。他們的公共GitHub曆史是空空如也的。

學習新的東西是好事情,但是不要混淆了實際的“建築原料”。那些事物、那些支付你薪水的才是實際的“建築物”。停止過度的制造。你不是在制造下一個Facebook。(不論是)Promises vs。(還是)generator vs。異步等待對我來說都是有争議的,因為等到有人在讨論中回答了線程的問題的(時候),我已經寫好了我的回調(函數)(并且使用CoffeeScript來以比ES5/6/7快2倍的速度完成(任務))

最後,最好的練習就是實踐,最最好的就是去掌握最本質的(知識)。閱讀源碼,在代碼中嘗試新的東西并且最重要的就是你自己寫大量的代碼。現在,在這個點上,停止閱讀,去實際操作吧!

https://mp.weixin.qq.com/s/U2atddlrVuEzxtZBqT0dTg