爲何要使用Node.js?

介紹

JavaScript的流行給它自己帶來許多變化,Web開發的面貌也發生了巨大的改變。如今JavaScript不只能夠運行在瀏覽器上,甚至能夠運行在服務器上,像Flash或者Java Applets那樣被包裝在沙盒環境中運行,這在幾年前這是很難想象的。前端

在深刻Node.js以前,你也許想知道使用JavaScript跨技術棧開發的優點,能夠統一開發語言和數據格式(JSON),使開發者優化開發資源的使用。這些優點在Node.js和JavaScript的技術棧中更加明確,關於這些咱們不討論太多,這是你將Node.js加入到技術棧後最明顯的優點。java

維基百科中描述:「Node.js是Google V8引擎,libuv做爲平臺抽象層,JavaScript編寫的核心庫封裝編譯的。」不只如此,值得注意的是Node.js的做者Ryan Dahl目的是構建一個有實時推送能力的網站。靈感來自相似Gmail的應用。在Node.js中,他提供給開發者事件驅動、非阻塞I/O的模型。node

有人說:Node.js在使用WebSocket的推送技術建立的實時Web應用中大放異彩。爲何它引發巨大的改變?在通過長達20多年基於無狀態請求響應模型中,咱們最終有了實時、全雙工通訊的Web應用,瀏覽器和服務器均可以初始化創建鏈接,自由的交換數據。這和傳統的基於客戶端初始化鏈接的Web響應模式有明顯的對比。nginx

有人也許會說,咱們已經以Flash和Java Applets的形式使用過不少年了。但實際上它們只是運行在沙盒環境裏,經過Web傳輸協議發送到客戶端,它們孤立地運行在非標準端口上,可能會引入好比權限問題。web

由於這些優勢,如今Node.js在那依賴本身獨特利益的大公司的技術棧裏扮演着關鍵性的角色。Node.js基金會整理了全部最佳實踐,關於企業爲何應該考慮使用Node.js。你能夠在一篇短文中找到。算法

這篇文章中,我不只討論那些已經實現的優勢,還會結合一些經典的Web應用模型,告訴你爲何你要使用Node.js,以及爲何不要使用Node.js。數據庫

它是怎樣工做的?

Node.js最主要的特色:使用非阻塞、事件驅動I/O模型使其輕量、高效,可以構建數據密集型、實時的跨平臺應用。這說明Node.js並非一顆主宰整個Web開發世界的銀彈。相反,它是一個解決特殊需求的平臺。明白這些是必要的,不要使用Node.js處理CPU密集型業務,若是你真的這麼作了,咱們先前說過關於Node.js的優勢都將不復存在。Node.js真正適合的是構建快速的、可擴展的網絡應用,他的吞吐率可以勝任巨量的併發鏈接。express

和傳統的Web服務技術相比,每一個請求到來建立一個新的線程,系統爲每一個線程分配內存,最終由於內存不夠而透支,Node.js工做在單線程,使用非阻塞I/O調用,可以承受上萬的併發鏈接。咱們很快得出一個結論:假設每建立一個線程系統爲它分配2M內存,在一臺8G內存的系統上它的最大併發數是4000(這個結論來自Michael Abernethy的文章《Just what is Node.js?》,於2011年出版在IBM developerWorks,不幸的是如今不能閱讀了),加上線程上下文切換的花費,這是使用傳統Web服務技術的場景,Node.js實現的可擴展性遠遠超過它。redux

固然全部客戶端請求都使用同一個線程是有問題的,它是Node.js應用的一個潛在陷阱。首先,大量的計算會阻塞單線程直到計算完成。第二,開發者必定要注意不要讓異常冒泡到應用頂部,這可能使整個Node.js程序崩潰。後端

避免異常冒泡到程序頂部,能夠將錯誤當作回調函數的參數。即便有些未捕獲的異常,開發工具可以監視Node.js進程,而且完成必要的崩潰實例恢復(當前用戶的session是沒有辦法恢復的),最常使用的工具就是forever,或者外部系統工具,也能夠直接重啓。

NPM: Node包管理工具

當咱們討論Node.js時,須要瞭解一下NPM,它是內置用來管理Node.js包的工具,安裝Node.js時就會默認安裝它。NPM的思想和Ruby的Gem十分類似:一個可公開的、可重用的組件庫,可經過在線倉庫輕鬆安裝,可以進行版本和依賴項管理。

下面是一些NPM包,你能夠在NPM官網找到它們,或者使用NPM命令行工具下載到你的Node.js項目裏。NPM是一個開發的生態系統,任何人能夠發佈本身的NPM模塊,並在NPM官網上找到它。你能夠在Beginner’s Guide上找到一份簡介,還有一份開發NPM包的指南開發NPM包的指南.

這是常常用到的一些NPM包:

  • express - Express.js是一個受Sinatra啓發的Node.js的Web開發框架,它是今天大部分Node.js應用程序的事實上的標準。

  • koa - 和Express是同一個做者,基於中間件機制的Web框架,比Express更加輕量。

  • socket.io - Node.js服務端實時應用的框架。

  • request - 一個HTTP客戶端請求工具。

  • async - async是一個用來處理JavaScript異步操做的工具庫。

  • bluebird - bluebird實現了Promise/A+規範,是一款性能很是好的Promise工具庫.

  • lodash and underscore and Ramda -是JavaSciprt的擴展庫,提供了豐富的方法。

  • debug - 開發過程當中用到的調試工具。

  • forever and nodemon - 經常使用的進程守護工具,上文提到過,能夠在開發模式下保護你的進程。

能夠用Node.js實現的應用

聊天室

聊天是典型的實時、多用戶應用。在當時IRC經過許多專有和開放的協議運行在不標準的端口上,如今在Node.js環境下,咱們能夠在標準的80端口上,實現這些聊天應用。

能夠說聊天應用是體驗Node.js優勢最好的例子,聊天應用輕量化、高流量,數據密集型(計算和處理時間短,最簡單作一次轉發)、跨終端、也是學習Node.js絕佳的例子,它包含了大多數在一個典型的Node.js應用中用到的模式。

分析一下聊天室是如何工做的。

最簡單的例子,在咱們的站點上只有一個聊天房間,所用的用戶採用一對多的形式交換消息。假設咱們的房間裏有三個已經創建鏈接的用戶。

在服務端,咱們有一個簡單的Express.js的應用,它實現兩個功能:1.當咱們請求根目錄時,它返回一個包含消息面板,用來發送消息的按鈕,還有輸入框的網頁。2.一個websocket服務,監聽新消息併發送給客戶端。

在客戶端,咱們有一個監聽兩個事件的頁面,其中一個監聽發送按鈕點擊事件,獲取輸入框中的消息,並經過websocket發送到服務端,另外一個事件監聽websocket客戶端新消息(這個消息來源於其餘用戶,服務端轉發給全部在這個聊天房間的用戶,而且客戶端顯示消息)。

當一個用戶發送消息,會通過以下幾步:

  1. 瀏覽器監聽發送按鈕點擊,JavaScript處理事件,從輸入框中獲取消息內容,websocket發送消息。

  2. 服務端webSocket鏈接收到消息,經過使用broadcast方法,進一步將它轉發給其餘創建鏈接的用戶。

  3. 全部用戶經過客戶端websocket收到了來自服務端的推送消息,客戶端將獲得的消息,追加到頁面消息面板的適當位置。

這是最簡單的例子了,若是你想讓它更加健壯,你可使用如Redis這樣的高速緩存,或者更高級一點,用消息隊列處理客戶端的消息分發,而且創建更強大的鏈接機制,用來減小創建臨時鏈接的損失,還能夠爲已經註冊的用戶保存離線消息。無論你是否能實現這些功能,Node.js的最基本的功能還是處理事件和併發鏈接,而且保證用戶體驗的流暢性。

非關係型數據庫數據接口

Node.js不只在實時應用上作的很出色,它和很是適合從非關係型數據庫讀取數據。Node.js使用JSON存儲數據,能夠無阻抗失配,不須要數據轉換。

舉個例子,若是你使用用Rails開發,你會將JSON數據轉換爲二進制數據,而後經過Http協議發送到瀏覽器,數據須要轉換爲JSON格式才能被Backbone.js,Angular.js等框架或者普通Ajax調用。若是你使用Node.js開發,你能夠經過REST API返回JSON對象給瀏覽器使用。此外,你也不須要擔憂在讀寫數據庫(MongoDB)時會發生數據轉換錯誤。總之,你能夠沒必要在客戶端、服務器、數據庫使用統一序列化格式。

隊列

若是你的應用有高併發的數據,數據庫會成爲應用的瓶頸。上文提到,Node.js能夠輕鬆地處理高併發鏈接,可是數據庫訪問倒是阻塞的操做,在這種狀況下,咱們就有麻煩了。解決方案就是,咱們先接受客戶端的請求,並返回結果,而後才真正的寫到數據庫中。

使用這種方法,系統能在高負載的狀況下保證響應能力,尤爲是在客戶端不須要確認是否存數據存儲成功的狀況下。最典型的例子就是:日誌或者記錄用戶行爲的數據,批次處理而且不會馬上使用的狀況;操做不須要馬上作出反應(就像Facebook更新點贊數據),在使用NoSQL的狀況下是可行的。

數據經過某種緩存或者消息隊列(如:RabbitMQ,ZeroMQ)進行排隊,等待被數據庫寫線程批量寫入,或者計算密集型的後端服務進行處理。類似的行爲能夠經過其餘語言或者框架來實現,可是在相同的硬件下,Node.js能保持更高的吞吐量。

數據流

在傳統的Web平臺,HTTP請求和響應被當作孤立的事件來對待;實際上他們都是數據流。這個事實被Node.js利用構建一些很酷的特性,例如:咱們能夠在文件上傳過程當中就進行處理,因爲數據是以流的形式傳輸過來,咱們能夠在線處理它。能夠用來作實時語音或視頻的編碼,在不一樣的數據源之間作代理。

代理

Node.js和容易搭建一個服務端代理,它能夠以非阻塞的方式處理大量併發鏈接。尤爲是用在爲不一樣響應時間的服務作代理,或者從多個源點收集數據。

舉個例子:服務端應用須要和第三方資源溝通,從多個源點拉取數據,或者將圖像視頻等資源存儲到第三方服務。

儘管專用代理服務確實存在,你能夠在代理基礎設施不全或者須要本地開發的解決方案時用Node.js來實現。在開發時你可使用Node.js服務搭建靜態資源客戶端應用,代理API請求。在生產環境下你可使用專用代理服務,如:nginx、HAProxy等。

中間層

讓咱們回到應用水平。中間人交易軟件在桌面軟件占主導地位,但很容易用實時網絡解決方案代替,它用來跟蹤股票價格,進行計算/技術分析,並建立圖表。若是是基於Web的實時應用的解決方案,經紀人輕鬆地切換工做站或工做場所。

應用監控

另外一種常見的場景,在Node.js中使用WebSocket技術跟蹤網站訪問者並實時可視化他們的交互。你能夠從你的用戶那裏收集實時的統計數據,甚至能夠經過在你的漏斗中到達一個特定的點,打開一個通訊通道來與訪問者進行有針對性的交互,從而將其移動到下一個層次。(若是你感興趣,能夠去了解CANDDi,它已經把這個想法產品化了)。

系統監控

如今咱們聊一條基礎設施方面的問題。設想一下,有一個Sass平臺想要提供給用戶一個服務監控頁面,例如GitHub’s status page。使用Node.js的事件循環機制,咱們能夠構建一個強大的信息板,來監控服務器的狀態,以異步的方式將數據經過WebSocket發送到客戶端。

無論是內部仍是公衆服務,均可以經過這種技術實時報告狀態。咱們進一步推進這個想法,而後想象一個工做在電信運營商的Network Operations Center (NOC)監控應用,雲/網絡/主機提供商,或者是一些金融機構,都運行在Node.js和WebSockets技術棧上,而不是java或java小應用程序。

注意:不要試圖使用Node.js構建硬實時系統,即那些要求一致響應時間的系統。Erlang構建這類應用或許是更好的選擇

Node.js適合用在哪?

web應用程序

使用Express.js框架能夠在服務器上構建一個傳統的Web應用,有一種說法,Node.js的請求響應模型用來渲染HTML頁面不是最好的用處。這個觀點是有爭議的,他們的考慮以下:

同意的觀點:

  • 若是你的應用沒有CPU密集的處理,你可使用Node.js構建自上而下的應用,或者作最底層對象關係數據庫(MongoDB)的讀寫,這大大簡化了開發。

  • 爬蟲抓取到一個完成的HTML響應,要比獲得一個單頁面或者使用WebSocket的應用,對SEO更加友好。

反對的觀點:

  • 任何CPU密集型的業務將會阻塞Node.js的響應,若是沒有這種業務單線程表現很好,相反的,你能夠增長CPU的運算量試試。

  • 使用Node.js時,任何關係型數據庫都是至關痛苦的(詳情見下文),若是你肯定要用關係型數據庫,幫本身一個忙,你能夠試試Rails,Django,或者ASP.Net。

有一個替代CPU密集型業務的解決方案,建立一個告訴可伸縮的消息隊列後臺程序,Node.js像前臺接待員同樣異步地接受客戶端請求。

Node.js不適合用在哪?

使用關係型數據庫的Web應用程序

Node.js的Express.js和Ruby on Rails進行比較,後端訪問關係數據庫乾淨的決策比較受到支持。

Node.js關係數據庫工具發展仍在早期階段;它們工做的至關不成熟也不友好。另外一方面,Rails自動提供數據訪問設置權開箱與DB模式遷移的支持工具和其餘Gems。Rails及其對等框架具備成熟的、已證明的活動記錄或數據映射器數據訪問層實現,若是你試圖以純JavaScript複製它們,你會很是懷念這段經歷。

你若你還想繼續走Node.js這條路,準備好掉幾根頭髮吧。記得關注一下Sequelize 和 Node ORM2二者都還不成熟,但最終可能會迎頭遇上。

將Node.js單獨用做前端是可能的,並且並很多見,同時保持Rails後端和對關係數據庫的簡單訪問。

沉重的服務端計算

當涉及到大量的計算,Node.js是否是最好的平臺。你確定不想使用Node.js建一個斐波納契計算服務器,總之,任何CPU密集型操做都會使Node.js事件驅動,非阻塞I/O的的模型變得毫無做用,由於請求會被阻塞,由於線程被你的數字梳理給佔據了。

如上所述,Node.js使用單線程而且只使用單核CPU,若是你打算在多核CPU上部署服務,Node.js核心團隊開發了集羣模塊。你也能夠創建多個Node.js引用實例,讓後經過Nginx代理到它們。

在使用集羣是,你仍是應該將計算量重的操做放到像RabbitMQ這樣的消息隊列裏,在合適的時候拿出來處理。

儘管最初的後臺處理可能在同一臺服務器上運行,但這種方法具備很是高的可伸縮性。這些後臺處理服務能夠很容易地分發到分離的worker服務器,而無需配置前向Web服務器的負載。

固然,你能夠在其餘平臺上使用同樣的作法,但Node.js有高的請求/秒的吞吐量,咱們已經談過,由於每一個請求是一個小的任務處理的很是快速和有效的。

總結

咱們從理論到實踐討論Node.js,從它的目標和抱負開始,到它的甜頭和陷阱。當開發者遇到Node.js的問題時,認爲阻塞是萬惡之源,99%的緣由是濫用Node.js形成的。

記住,Node.js不是爲了解決計算擴展問題而產生的,而是爲了解決I/O擴展問題,在這方面它作的很出色。

爲何使用Node.js?若是您使用的狀況不包含CPU密集型操做或訪問任何阻塞的資源,你能夠利用Node.js的好處,構建快速和可擴展的網絡應用。歡迎來到實時Web應用。


往日精選:

前端如何優雅切圖

僅使用CSS,帶你建立一個漂亮的動畫加載頁面

使用 React 實現頁面過渡動畫僅需4個步驟

像數據庫同樣設計你的 redux 數據結構

爲何我認爲數據結構與算法對前端開發很重要?

深刻貫徹閉包思想,全面理解JS閉包造成過程

提升 | 10個JavaScript難點

JavaScript數據結構系列終篇——全系列索引

如何寫好技術簡歷 —— 實例、模板及工具

29個前端工程師和設計師必備的Chrome插件

2017年前端開發技術棧

掌握Chrome開發工具:新一代前端開發技術

5個你可能不知道的CSS屬性

測量 web 性能,很是簡單


既然讀到這裏了,那就推薦一個有意思的公衆號:

充實的腦洞

天天深夜給你看一些有趣的東西

長按二維碼關注




小手一抖,資料全有。長按二維碼關注京程一燈,閱讀更多技術文章和業界動態。


本文分享自微信公衆號 - 前端先鋒(jingchengyideng)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索