1. 程式人生 > 其它 >node.js進階學習

node.js進階學習

簡介

如果您聽說過 Node,或者閱讀過一些文章,宣稱 Node 是多麼多麼的棒,那麼您可能會想:“Node 究竟是什麼東西?”儘管不是針對所有人的,但 Node 可能是某些人的正確選擇。

為試圖解釋什麼是 Node.js,本文探究了它能解決的問題,它如何工作,如何執行一個簡單應用程式,最後,Node 何時是和何時不是一個好的解決方案。本文不涉及如何編寫一個複雜的 Node 應用程式,也不是一份全面的 Node 教程。閱讀本文應該有助於您決定是否應該學習 Node,以便將其用於您的業務。

Node 旨在解決什麼問題?

Node 公開宣稱的目標是 “旨在提供一種簡單的構建可伸縮網路程式的方法”。當前的伺服器程式有什麼問題?我們來做個數學題。在 Java™ 和 PHP 這類語言中,每個連線都會生成一個新執行緒,每個新執行緒可能需要 2 MB 配套記憶體。在一個擁有 8 GB RAM 的系統上,理論上最大的併發連線數量是 4,000 個使用者。隨著您的客戶端基礎的增長,您希望您的 web 應用程式支援更多使用者,這樣,您必須新增更多伺服器。當然,這會增加業務成本,尤其是伺服器成本、運輸成本和人工成本。除這些成本上升外,還有一個技術問題:使用者可能針對每個請求使用不同的伺服器,因此,任何共享資源都必須在所有伺服器之間共享。例如,在 Java 中,靜態變數和快取需要在每個伺服器上的 JVMs 之間共享。這就是整個 web 應用程式架構中的瓶頸:一個伺服器能夠處理的併發連線的最大數量。

Node 解決這個問題的方法是:更改連線連線到伺服器的方式。每個連線都建立一個程序,該程序不需要配套記憶體塊,而不是為每個連線生成一個新的 OS 執行緒(並向其分配一些配套記憶體)。Node 聲稱它絕不會死鎖,因為它根本不允許使用鎖,它不會直接阻塞 I/O 呼叫。Node 還宣稱,執行它的伺服器能支援數萬個併發連線。事實上,Node 通過將整個系統中的瓶頸從最大連線數量更改到單個系統的流量來改變伺服器面貌。

現在您有了一個能處理數萬條併發連線的程式,那麼您能通過 Node 實際構建什麼呢?如果您有一個 web 應用程式需要處理這麼多連線,那將是一件很 “恐怖” 的事!那是一種 “如果您有這個問題,那麼它根本不是問題” 的問題。在回答上面的問題之前,我們先看看 Node 如何工作以及它被設計的如何執行。

Node 肯定不是什麼

沒錯,Node 是一個伺服器程式。但是,它肯定 像 Apache 或 Tomcat。那些伺服器是獨立伺服器產品,可以立即安裝並部署應用程式。通過這些產品,您可以在一分鐘內啟動並執行一個伺服器。Node 肯定不是這種產品。Apache 能新增一個 PHP 模組來允許開發人員建立動態 web 頁,使用 Tomcat 的程式設計師能部署 JSPs 來建立動態 web 頁。Node 肯定不是這種型別。

在 Node 的早期階段(當前是 version 0.4.6),它還不是一個 “執行就緒” 的伺服器程式,您還不能安裝它,向其中放置檔案,擁有一個功能齊全的 web 伺服器。即使是要實現 web 伺服器在安裝完成後啟動並執行這個基本功能,也還需要做大量工作。

Node 如何工作

Node 本身執行 V8 JavaScript。等等,伺服器上的 JavaScript?沒錯,您沒有看錯。伺服器端 JavaScript 是一個相對較新的概念,這個概念是大約兩年前在 developerWorks 上討論 Aptana Jaxer 產品時提到的(參見 參考資料)。儘管 Jaxer 一直沒有真正流行,但這個理念本身並不是遙不可及的 — 為何不能在伺服器上使用客戶機上使用的程式語言?

什麼使 V8?V8 JavaScript 引擎是 Google 用於他們的 Chrome 瀏覽器的底層 JavaScript 引擎。很少有人考慮 JavaScript 在客戶機上實際做了些什麼?實際上,JavaScript 引擎負責解釋並執行程式碼。使用 V8,Google 建立了一個以 C++ 編寫的超快直譯器,該直譯器擁有另一個獨特特徵;您可以下載該引擎並將其嵌入任何 應用程式。它不僅限於在一個瀏覽器中執行。因此,Node 實際上使用 Google 編寫的 V8 JavaScript 引擎並將其重建為在伺服器上使用。太完美了!既然已經有一個不錯的解決方案可用,為何還要建立一種新語言呢?

事件驅動程式設計

許多程式設計師接受的教育使他們認為,面向物件程式設計是完美的程式設計設計,而對其他程式設計方法不屑一顧。Node 使用一個所謂的事件驅動程式設計模型。

清單 1. 客戶端上使用 jQuery 的事件驅動程式設計

// jQuery code on the client-side showing how Event-Driven programming works

// When a button is pressed, an Event occurs - deal with it
// directly right here in an anonymous function, where all the
// necessary variables are present and can be referenced directly
$("#myButton").click(function(){
     if ($("#myTextField").val() != $(this).val())
         alert("Field must match button text");
});

實際上,伺服器端和客戶端沒有任何區別。沒錯,這沒有按鈕點選操作,也沒有向文字欄位鍵入的操作,但在一個更高的層面上,事件正在 發生。一個連線被建立 — 事件!資料通過連線接收 — 事件!資料通過連線停止 — 事件!

為什麼這種設定型別對 Node 很理想?JavaScript 是一種很棒的事件驅動程式語言,因為它允許匿名函式和閉包,更重要的是,任何寫過程式碼的人都熟悉它的語法。事件發生時呼叫的回撥函式可以在捕獲事件處編寫。這樣,程式碼容易編寫和維護,沒有複雜的面向物件框架,沒有介面,沒有在上面架構任何內容的潛能。只需監聽事件,編寫一個回撥函式,然後,事件驅動程式設計將照管好一切!

回頁首

示例 Node 應用程式

最後,我們來看一些程式碼!讓我們將討論過的所有內容綜合起來,建立我們的第一個 Node 應用程式。由於我們已經知道,Node 對於處理高流量應用程式很理想,我們就來建立一個非常簡單的 web 應用程式 — 一個為實現最大速度而構建的應用程式。下面是 “老闆” 交代的關於我們的樣例應用程式的具體要求:建立一個隨機數字生成器 RESTful API。這個應用程式應該接受一個輸入:一個名為 “number” 的引數。然後,應用程式返回一個介於 0 和該引數之間的隨機數字,並將生成的數字返回呼叫者。由於 “老闆” 希望它成為一個廣泛流行的應用程式,因此它應該能處理 50,000 個併發使用者。我們來看看程式碼:

清單 2. Node 隨機數字生成器

// these modules need to be imported in order to use them.
// Node has several modules.  They are like any #include
// or import statement in other languages
var http = require("http");
var url = require("url");

// The most important line in any Node file.  This function
// does the actual process of creating the server.  Technically,
// Node tells the underlying operating system that whenever a
// connection is made, this particular callback function should be
// executed.  Since we're creating a web service with REST API,
// we want an HTTP server, which requires the http variable
// we created in the lines above.
// Finally, you can see that the callback method receives a 'request'
// and 'response' object automatically.  This should be familiar
// to any PHP or Java programmer.
http.createServer(function(request, response) {

     // The response needs to handle all the headers, and the return codes
     // These types of things are handled automatically in server programs
     // like Apache and Tomcat, but Node requires everything to be done yourself
     response.writeHead(200, {"Content-Type": "text/plain"});

     // Here is some unique-looking code.  This is how Node retrieves
     // parameters passed in from client requests.  The url module
     // handles all these functions.  The parse function
     // deconstructs the URL, and places the query key-values in the
     // query object.  We can find the value for the "number" key
     // by referencing it directly - the beauty of JavaScript.
     var params = url.parse(request.url, true).query;
     var input = param.number;

     // These are the generic JavaScript methods that will create
     // our random number that gets passed back to the caller
     var numInput = new Number(input);
     var numOutput = new Number(Math.random() * numInput).toFixed(0);
     
     // Write the random number to response
     response.write(numOutput);
     
     // Node requires us to explicitly end this connection.  This is because
     // Node allows you to keep a connection open and pass data back and forth,
     // though that advanced topic isn't discussed in this article.
     response.end();

   // When we create the server, we have to explicitly connect the HTTP server to
   // a port.  Standard HTTP port is 80, so we'll connect it to that one.
}).listen(80);

// Output a String to the console once the server starts up, letting us know everything
// starts up correctly
console.log("Random Number Generator Running...");

啟動應用程式

將上面的程式碼放到一個名為 “random.js” 的檔案中。現在,要啟動這個應用程式並執行它(進而建立 HTTP 伺服器並監聽埠 80 上的連線),只需在您的命令提示中輸入以下命令:% node random.js。下面是伺服器已經啟動並執行時它看起來的樣子:

root@ubuntu:/home/moilanen/ws/mike# node random.js
Random Number Generator Running...

訪問應用程式

應用程式已經啟動並執行。Node 正在監聽任何連線,我們來測試一下。由於我們建立了一個簡單的 RESTful API,我們可以使用我們的 web 瀏覽器來訪問這個應用程式。鍵入以下地址(確保您完成了上面的步驟):http://localhost/?number=27。

您的瀏覽器視窗將更改到一個介於 0 到 27 之間的隨機數字。單擊瀏覽器上的 “重新載入” 按鈕,將得到另一個隨機數字。就是這樣,這就是您的第一個 Node 應用程式!

回頁首

Node 對什麼有好處?

到此為止,應該能夠回答 “Node 是什麼” 這個問題了,但您可能還不清楚什麼時候應該使用它。這是一個需要提出的重要問題,因為 Node 對有一些東西有好處,但相反,對另一些東西而言,目前 Node 可能不是一個好的解決方案。您需要小心決定何時使用 Node,因為在錯誤的情況下使用它可能會導致一個多餘編碼的 LOT。

它對什麼有好處?

正如您此前所看到的,Node 非常適合以下情況:您預計可能有很高的流量,而在響應客戶端之前伺服器端邏輯和處理所需不一定是巨大的。Node 表現出眾的典型示例包括:

  • RESTful API 提供 RESTful API 的 web 服務接收幾個引數,解析它們,組合一個響應,並返回一個響應(通常是較少的文字)給使用者。這是適合 Node 的理想情況,因為您可以構建它來處理數萬條連線。它還不需要大量邏輯;它只是從一個數據庫查詢一些值並組合一個響應。由於響應是少量文字,入站請求時少量文字,因此流量不高,一臺機器甚至也可以處理最繁忙的公司的 API 需求。
  • Twitter 佇列 想像一下像 Twitter 這樣的公司,它必須接收 tweets 並將其寫入一個數據庫。實際上,每秒幾乎有數千條 tweets 達到,資料庫不可能及時處理高峰時段需要的寫入數量。Node 成為這個問題的解決方案的重要一環。如您所見,Node 能處理數萬條入站 tweets。它能迅速輕鬆地將它們寫入一個記憶體排隊機制(例如 memcached),另一個單獨程序可以從那裡將它們寫入資料庫。Node 在這裡的角色是迅速收集 tweet 並將這個資訊傳遞給另一個負責寫入的程序。想象一下另一種設計 — 一個常規 PHP 伺服器自己試圖處理對資料庫的寫入 — 每個 tweet 將在寫入資料庫時導致一個短暫的延遲,這是因為資料庫呼叫正在阻塞通道。由於資料庫延遲,一臺這樣設計的機器每秒可能只能處理 2000 條入站 tweets。 每秒 100 萬條 tweets 需要 500 個伺服器。相反,Node 能處理每個連線而不會阻塞通道,從而能捕獲儘可能多的 tweets。一個能處理 50,000 條 tweets 的 Node 機器只需要 20 個伺服器。
  • 映像檔案伺服器 一個擁有大型分散式網站的公司(比如 Facebook 或 Flickr)可能會決定將所有機器只用於服務映像。Node 將是這個問題的一個不錯的解決方案,因為該公司能使用它編寫一個簡單的檔案檢索器,然後處理數萬條連線。Node 將查詢映像檔案,返回檔案或一個 404 錯誤,然後什麼也不用做。這種設定將允許這類分散式網站減少它們服務映像、.js 和 .css 檔案等靜態檔案所需的伺服器數量。

它對什麼有壞處?

當然,在某些情況下,Node 並非理想選擇。下面是 Node 不擅長的領域:

  • 動態建立的頁 目前,Node 沒有提供一種預設方法來建立動態頁。例如,使用 JavaServer Pages (JSP) 技術時,可以建立一個在 <% for (int i=0; i<20; i++) { } %> 這樣的 JSP 程式碼段中包含迴圈的 index.jsp 頁。Node 不支援這類動態的、HTML 驅動的頁面。同樣,Node 不太適合作為 Apache 和 Tomcat 這樣的網頁伺服器。因此,如果您想在 Node 中提供這樣一個伺服器端解決方案,必須自己編寫整個解決方案。PHP 程式設計師不想在每次部署 web 應用程式時都編寫一個針對 Apache 的 PHP 轉換器,當目前為止,這正是 Node 要求您做的。
  • 關係資料庫重型應用程式 Node 的目的是快速、非同步和非阻塞。資料庫並不一定分享這些目標。它們是同步和阻塞的,因為讀寫時對資料庫的呼叫在結果生成之前將一直阻塞通道。因此,一個每個請求都需要大量資料庫呼叫、大量讀取、大量寫入的 web 應用程式非常不適合 Node,這是因為關係資料庫本身就能抵銷 Node 的眾多優勢。(新的 NoSQL 資料庫更適合 Node,不過那完全是另一個主題了。)

回頁首

結束語

問題是 “什麼是 Node.js?” 應該已經得到解答。閱讀本文之後,您應該能通過幾個清晰簡潔的句子回答這個問題。如果這樣,那麼您已經走到了許多編碼員和程式設計師的前面。我和許多人都談論過 Node,但它們對 Node 究竟是什麼一直很迷惑。可以理解,他們具有的是 Apache 的思維方式 — 伺服器是一個應用程式,將 HTML 檔案放入其中,一切就會正常運轉。而 Node 是目的驅動的。它是一個軟體程式,使用 JavaScript 來允許程式設計師輕鬆快速地建立快速、可伸縮的 web 伺服器。Apache 是執行就緒的,而 Node 是編碼就緒的。

Node 完成了它提供高度可伸縮伺服器的目標。它並不分配一個 “每個連線一個執行緒” 模型,而是使用一個 “每個連線一個流程” 模型,只建立每個連線需要的記憶體。它使用 Google 的一個非常快速的 JavaScript 引擎:V8 引擎。它使用一個事件驅動設計來保持程式碼最小且易於閱讀。所有這些因素促成了 Node 的理想目標 — 編寫一個高度可伸縮的解決方案變得比較容易。

與理解 Node 什麼同樣重要的是,理解它不是 什麼。Node 並不是 Apache 的一個替代品,後者旨在使 PHP web 應用程式更容易伸縮。事實確實如此。在 Node 的這個初始階段,大量程式設計師使用它的可能性不大,但在它能發揮作用的場景中,它的表現非常好。

將來應該期望從 Node 得到什麼呢?這也許是本文引出的最重要的問題。既然您知道了它現在的作用,您應該會想知道它下一步將做什麼。在接下來的一年中,我期待著 Node 提供與現有的第三方支援庫更好地整合。現在,許多第三方程式設計師已經研發了用於 Node 的外掛,包括新增檔案伺服器支援和 MySQL 支援。希望 Node 開始將它們整合到其核心功能中。最後,我還希望 Node 支援某種動態頁面模組,這樣,您就可以在 HTML 檔案中執行在 PHP 和 JSP(也許是一個 NSP,一個 Node 伺服器頁)中所做的操作。最後,希望有一天會出現一個 “部署就緒” 的 Node 伺服器,可以下載和安裝,只需將您的 HTML 檔案放到其中,就像使用 Apache 或 Tomcat 那樣。Node 現在還處於初始階段,但它發展得很快,可能不久就會出現在您的視野中。

參考資料

學習

============================================================================

node.js高階學習可以參考

Node.js:用JavaScript寫伺服器端程式-介紹並寫個MVC框架