JavaScript 的日益發展帶來了許多變化,而當今的 Web 開發面貌已經變得截然不同。在幾年前是很難想像在伺服器上運行 JavaScript 的。
在深入研究Node.js之前,你可能想了解使用跨堆疊的JavaScript 有什麼好處,它統一了語言和資料格式(JSON),允許你以最佳的方式重複使用開發人員資源。將 Node.js 合併到技術棧中是一個關鍵優勢。
Node.js 是一個基於 Chrome 的名為 V8 的 JavaScript 引擎所建構的 JavaScript 運行環境。值得注意的是,Node.js 的創建者 Ryan Dahl 的“受到 Gmail 等應用程式的啟發”,目標是為了開發一個具有實時推送功能的網站。在 Node.js 中,他提供了一個用於處理非阻塞事件驅動的 I/O 工具。 【影片教學推薦:nodejs 教學 】
用一句話來概括:Node.js 在基於websockets 推送技術的即時 Web 應用中大放異彩。在過去的20 多年來我們一直在使用基於無狀態請求- 響應模式的無狀態Web 應用,現在終於擁有了能夠實時雙向連接的Web 應用,其中客戶端和伺服器都可以啟動通信,並允許它們自由地交換數據。
這與典型的總是由客戶端發起通訊的 Web 回應模式形了成鮮明的對比。此外它也同樣基於在標準連接埠 80 上執行的開放 Web 技術堆疊(HTML,CSS和JS)。
有人可能會爭辯說,我們多年來一直以 Flash 和 Java Applet 的形式做到這一點 —— 但實際上,這些只是使用 Web 作為傳輸協定將資料傳給客戶端的沙盒環境。此外,它們是隔離運行的,通常在非標準連接埠上運行,這可能需要額外的權限。
憑藉其優勢,Node.js 在依賴其獨特優勢的眾多知名公司的技術堆疊中發揮著關鍵作用。 Node.js 基金會幾乎已經整合了所有最好的想法,可以在 Node.js 基金會的案例研究頁面上找到關於為什麼企業應該考慮 Node.js 的簡短PPT。
在本文中,我將不僅要討論如何使用這些優勢,還要討論為什麼 你可能想要使用Node.js ,並用一些經典的Web 應用程式模型作為範例。
Node.js 的主要想法是:在面向跨分散式裝置運行的資料密集型的即時程式時,使用非阻塞、事件驅動的 I/O 來確保輕量和高效能。
這讀起來很拗口。
這意味著 Node.js 不是 一個即將成為主宰 Web 開發界的能夠解決一切的新平台。 相反,它是一個滿足特定需求的平台。 要理解這一點絕對是有必要的。你絕不希望將 Node.js 用於 CPU 密集型的操作;實際上,將它用於進行大量繁重運算的場合將會消除它幾乎所有的優點。 Node.js 真正發揮作用的地方在於建立快速、可擴展的網路應用,因為它能夠以高吞吐量處理大量並發連接,這相當於具有高可擴展性。
其底層的工作原理非常有趣。傳統的Web 服務技術每個連接(請求)都會產生一個新線程,佔用系統內存並最終受限於可用的最大內存,而Node.js 在單線程上運行,使用非阻塞I/O 調用,允許它支援數以萬計的並發連接(在event loop 中維持)。
快速計算:假設每個線程需要2 MB 內存,那麼在有8 GB 內存的系統上運行的話,理論上最多有4000 個並發連接(計算來自Michael Abernethy 的文章“Just what is Node .js?“,2011年在IBM developerWorks 上發布;不幸的是,這篇文章的鏈接現在已經失效了),這還沒算上線程之間的上下文切換的成本。這就是你通常在傳統的 Web 伺服器技術中處理的場景。透過避免所有這些問題,Node.js 實現了超過 1M 連接並發數的級別,以及 600k 的 websockets 並發連接數。
當然,編寫 Node.js 應用程式的潛在缺陷是存在客戶端請求之間共享單一執行緒的問題。首先,繁重的計算可能會阻塞 Node 的單一執行緒並導致 所有 客戶端出現問題(稍後會詳細說明),因為傳入的請求將被阻塞,直到計算完成為止。其次開發人員需要 非常小心,不要讓異常冒泡到到核心(最頂層)Node.js 事件循環,這將導致 Node.js 實例終止(程式崩潰)。
為了避免異常冒泡到頂層,常用技術是將錯誤作為回調參數傳遞回呼叫者(而不是像在其他環境中那樣拋出它們)。即使一些未被處理的異常冒泡到頂層,也有一些工具來監視Node.js 進程並執行必要的恢復崩潰 (雖然可能無法恢復到用戶會話的當前狀態),最常見的是Forever 模組。
在討論Node.js 時,一件絕對不應該被忽略的事是支援使用內建的npm 工具進行套件管理,預設為每個Node.js 環境都會安裝。 npm 模組的概念非常類似於 Ruby Gems:一組可透過線上儲存庫輕鬆安裝,具有版本和依賴關係管理的可重複使用元件,。
可以在 npm 網站上找到已打包模組的完整列表,也可以使用自動與 Node.js 一起安裝的 npm CLI 工具進行存取。模組生態系統對所有人開放,任何人都可以發布自己的模組,發布的模組將出現在 npm 儲存庫中。有關 npm 的簡介,請參閱初學者指南,以及 npm 發布教程中關於發布模組的部分。
一些很有用的npm 模組是:
線上聊天是最典型的即時多用戶應用,也是Node.js 的最佳案例:它是一個輕量級、高流量、資料密集型(但是低處理和計算)的應用程序,可分散式跨裝置運行。它也是一個很好的學習案例,因為它很簡單,但涵蓋了你在典型的 Node.js 程式中所使用的大部分範例。
讓我們試著描繪它是如何運作的。
假設一個最簡單的場景,在我們的網站上有一個聊天室,人們可以透過一對多(實際上是對所有人)的方式交換訊息。
在伺服器端,我們有一個簡單的Express.js 程序,它實作了兩件事:1) 一個GET 請求的處理程序,它提供了包含留言板和用於初始化新訊息輸入的「傳送」按鈕的功能,以及2) 用於偵聽websocket 用戶端發出的新訊息的w ebsockets 伺服器。
在客戶端,我們有一個HTML 頁面,其中設定了幾個處理程序,一個用於「發送」按鈕的點擊事件,它接收輸入訊息並將其發送到websocket,另一個用於偵聽新的傳入訊息並顯示在websockets 用戶端上(即伺服器希望客戶端顯示的其他使用者所傳送的訊息)。
當其中一個客戶發布訊息時,會發生以下情況:
這是最簡單的例子。對於更強大的解決方案,你可以使用基於 Redis 的簡單快取。或者在更進階的解決方案中,可以用訊息佇列作為訊息路由,還可以實現更強大的傳遞機制,例如可以在連線遺失或在客戶端脫機時儲存訊息。但無論你做出哪些改進,Node.js 仍將按照相同的基本原則運行:對事件做出反應,處理許多並發連接,並保持用戶體驗的流暢性。
雖然 Node.js 的確很適合開發即時應用,但它也很適合從物件資料庫(例如MongoDB)公開資料。 JSON 儲存的資料允許 Node.js 在物件與儲存資料一致和沒有資料轉換的情況下良好的運作。
例如,如果你正在使用Rails,那麼你需要從JSON 轉換為二進位模型,然後透過HTTP 再將它們轉為JSON 在React.js 或Angular.js 中使用,甚至可以用簡單的jQuery AJAX 進行呼叫。使用 Node.js,你可以透過 REST API 直接公開你的 JSON 物件來供客戶端使用。此外,從資料庫讀取或寫入時(如果你使用的是MongoDB),你無需擔心在 JSON 和其他任何內容之間進行轉換的問題。總之在客戶端、伺服器和資料庫中使用統一的資料序列化格式,可以避免多次轉換的麻煩。
如果你收到了大量並發數據,那麼你的資料庫可能會成為瓶頸。如上所述,Node.js 可以輕鬆地自己處理並發連接。但是因為資料庫存取是一種阻塞操作(在這種情況下),所以我們遇到了麻煩。解決方案是在資料真正寫入資料庫之前先確認客戶端的行為。
透過這種方法,系統可以在高負載下保持其回應性,這在客戶端不需要確認資料成功寫入時尤其有用。典型的例子包括:記錄或寫入使用者追蹤資料時進行分批處理;以及最終一致性(經常在NoSQL世界中使用)可以接受的不需要立即作出反映的操作(例如更新Facebook上的“Likes”計數)。
資料透過某種快取或訊息佇列(例如,RabbitMQ,ZeroMQ)排隊,並透過單獨的資料庫批次寫入過程,或由計算密集型後端服務進行消化,再寫入更好的能夠執行此類任務的平台。類似的行為可以用其他語言或框架實現,但不能在相同的硬體上實現,以維持相同的高吞吐量。
簡而言之:使用 Node,你可以將資料庫寫入先入到一個地方,稍後再去處理它們,就像它們已經被成功處理一樣。
在更傳統的Web平台中,HTTP 請求和回應被視為孤立事件,實際上他們是流。可以在 Node.js 中使用這個性質來建立一些很酷的功能。例如檔案可以被一邊上傳一邊處理,因為資料透過流進入,我們可以即時的去處理它。這可以用於即時音訊視訊編碼,以及在不同資料來源的之間進行代理(請參閱下一部分)。
把 Node.js 當作伺服器端代理程式是很容易的,它能夠以非阻塞方式處理大量的並發連線。這對於為代理不同回應時間的多個服務,或從多個來源收集資料的場景特別有用。
例如以下場景:當伺服器端程式與第三方資源進行通訊時,會從不同的來源提取數據,或將影像和視訊等資源儲存到第三方雲端服務上。
儘管有專用代理伺服器,但如果你沒有基礎的代理架構,或者你需要本地開發環境,那麼 Node 可能會對你有幫助。
讓我們回到應用程式。另一個可以輕鬆地用即時網路解決方案取代的例子是股票經紀人的交易軟體,它用於追蹤股票價格、執行計算、技術分析以及創建圖表。
如果切換到基於 Web 的即時解決方案,經紀人將可以輕鬆切換工作站或工作場所。很快,我們可能會開始在佛羅裡達州的海灘上看到它們...
#另一個常見的用例,其中Node-with-web -socket 完全適合:追蹤網站訪客並對他們的互動進行即時的可視化。你可以從用戶那裡即時收集統計信息,甚至可以透過在訪問渠道中特定的點來打開通信渠道,並與訪問者進行有針對性的互動,這種方案可以在這裡找到: CANDDi。
想像一下,如果你能夠即時了解訪客所做的事情,你將如何改善你的業務?透過使用 Node.js 的即時雙向套接字,現在就可以做到了。
在基礎設施方面,。例如想要為其使用者提供服務監控頁面的SaaS提供者(例如,GitHub狀態頁面)。透過 Node.js 事件循環,我們可以建立一個功能強大的基於 Web 的儀表板,以非同步方式檢查服務的狀態,並使用 websockets 將資料推送到客戶端。公司內部和公共服務的狀態都可以使用該技術即時報告。
注意:不要嘗試在 Node.js 中建立硬實時系統(即需要一致回應時間的系統)。對於那類應用程序,Erlang 可能是更好的選擇。
配合 Express.js 的 Node.js 也可在伺服器端建立經典 Web 應用程式。對於這種方法,有人支持也有人反對。以下是一些需要考慮的問題:
優點:
缺點:
CPU 密集型運算的一種替代方法是創建一個可高度擴展的MQ 支援環境,該環境具有後端處理功能,以使Node 成為一個前台“職員”,並以非同步方式處理客戶端請求。
例如,將Node.js Express.js 與Ruby on Rails 進行比較,當涉及關聯資料存取時,顯然後者更合適。
與競爭對手相比,Node.js 的關係型資料庫工具仍然相當原始。另一方面,Rails 提供了開箱即用的資料存取設定以及資料庫架構遷移支援工具,另外還有其他的 Gems。 Rails 及類似框架擁有成熟的且經過驗證的Active Record 或Data Mapper 資料存取層實現,如果你想嘗試在純JavaScript 中複製這些功能的話,那麼祝你好運。
不過,如果你真的傾向於用 JS 實現一切,請查看 Sequelize 和 Node ORM2。
如果只是把 Node.js 用作面向公眾的介面,同時用 Rails 後端存取關聯式資料庫,這是可以的,而且這種方式並不罕見。
當涉及到繁重的運算時,Node.js 並不是最好的平台。你絕對不想用 Node.js 去建立一個 Fibonacci 計算伺服器。通常,任何 CPU 密集型操作都會透過事件驅動的非阻塞 I/O 模型來抵銷 Node 提供的所有吞吐量優勢,因為當執行緒被數字運算佔用時,任何傳入請求都會被阻止。
如前面所說的,Node.js 是單執行緒的,只使用一個CPU核心。在多核心伺服器上新增並發性時,Node 核心團隊以 cluster module 的形式完成一些工作。你也可以很容易地在反向代理 nginx 的後面運行幾個 Node.js 伺服器實例。
如果使用群集,你仍然應該將所有繁重的計算放到在更合適的環境下編寫的後台進程中,並使它們透過像 RabbitMQ 這樣的訊息佇列伺服器進行通訊。
即使你所有的後台處理最初可能在同一台伺服器上運行,這種方法也有可能實現非常高的可擴展性。這些後台處理服務可以輕鬆地分發到單獨的工作伺服器,而無需對前置 Web 伺服器負載進行設定。
當然,你也可以在其他平台上使用相同的方法,但使用Node.js,你可以得到我們所討論的高reqs/sec 吞吐量,因為每個請求都是一個非常快速有效的小任務。
我們討論了 Node.js 從理論到實踐,從它的目標和抱負開始,並以其最佳點和陷阱結束。當人們遇到 Node 的問題時,它幾乎總是唄歸結為阻塞操作是所有邪惡的根源 —— 其中 99% 的直接原因是對 Node 的誤用。
請記住:不要用 Node.js 來解決計算擴充問題。它是為了解決 I/O 擴充問題而設計的,它做得確實很好。
所以,如果你的應用程式不包含 CPU 密集型操作,也不存取任何阻塞資源的話,可以利用 Node.js 的優勢,享受快速、可擴展的網路應用。
英文網址原文:https://medium.com/the-node-js-collection/why-the-hell-would-you-use-node-js-4b053b94ab8e
【影片教學推薦:nodejs影片教學 】
以上是為什麼要用Node.js?哪些場合可以使用 Node.js?的詳細內容。更多資訊請關注PHP中文網其他相關文章!