Node.js 到底是什麼?

簡介

若是您據說過 Node,或者閱讀過一些文章,宣稱 Node 是多麼多麼的棒,那麼您可能會想:「Node 到底是什麼東西?」 即使是在參閱 Node 的主頁以後,您甚至可能仍是 不明白 Node 爲什麼物?Node 確定不適合每一個程序員,但它多是某些程序員一直苦苦追尋的東西。html

爲試圖解釋什麼是 Node.js,本文將簡要介紹一些背景信息:它要解決的問題,它如何工做,如何運行一個簡單應用程序,最後,Node 在什麼狀況下是一個好的解決方案。本文不涉及如何編寫一個複雜的 Node 應用程序,也不是一份全面的 Node 教程。閱讀本文應該有助於您決定是否應該繼續學習 Node,以便將其用於您的業務。node

Node 旨在解決什麼問題?

Node 公開宣稱的目標是 「旨在提供一種簡單的構建可伸縮網絡程序的方法」。當前的服務器程序有什麼問題?咱們來作個數學題。在 Java™ 和 PHP 這類語言中,每一個鏈接都會生成一個新線程,每一個新線程可能須要 2 MB 的配套內存。在一個擁有 8 GB RAM 的系統上,理論上最大的併發鏈接數量是 4,000 個用戶。隨着您的客戶羣的增加,若是但願您的 Web 應用程序支持更多用戶,那麼,您必須添加更多服務器。固然,這會增長服務器成本、流量成本和人工成本等成本。除這些成本上升外,還有一個潛在技術問題,即用戶可能針對每一個請求使用不一樣的服務器,所以,任何共享資源都必須在全部服務器之間共享。鑑於上述全部緣由,整個 Web 應用程序架構(包括流量、處理器速度和內存速度)中的瓶頸是:服務器可以處理的併發鏈接的最大數量。程序員

Node 解決這個問題的方法是:更改鏈接到服務器的方式。每一個鏈接發射一個在 Node 引擎的進程中運行的事件,而不是爲每一個鏈接生成一個新的 OS 線程(併爲其分配一些配套內存)。Node 聲稱它毫不會死鎖,由於它根本不容許使用鎖,它不會直接阻塞 I/O 調用。Node 還宣稱,運行它的服務器能支持數萬個併發鏈接。web

如今您有了一個能處理數萬個併發鏈接的程序,那麼您能經過 Node 實際構建什麼呢?若是您有一個 Web 應用程序須要處理這麼多鏈接,那將是一件很 「恐怖」 的事!那是一種 「若是您有這個問題,那麼它根本不是問題」 的問題。在回答上面的問題以前,咱們先看看 Node 的工做原理以及它的設計運行方式。數據庫

Node 確定不是什麼?

沒錯,Node 是一個服務器程序。可是,基礎 Node 產品確定 像 Apache 或 Tomcat。本質上,那些服務器 「安裝就緒型」 服 務器產品,支持當即部署應用程序。經過這些產品,您能夠在一分鐘內啓動並運行一個服務器。Node 確定不是這種產品。Apache 能經過添加一個 PHP 模塊來容許開發人員建立動態 Web 頁,添加一個 SSL 模塊來實現安全鏈接,與此相似,Node 也有模塊概念,容許向 Node 內核添加模塊。實際上,可供選擇的用於 Node 的模塊有數百個之多,社區在建立、發佈和更新模塊方面很是活躍,一天甚至能夠處理數十個模塊。本文後面將討論 Node 的整個模塊部分。編程

Node 如何工做?

Node 自己運行 V8 JavaScript。等等,服務器上的 JavaScript?沒錯,您沒有看錯。對於只在客戶機上使用 JavaScript 的程序員而言,服務器端 JavaScript 多是一個新概念,但這個概念自己並不是高不可攀,所以爲什麼不能在服務器上使用客戶機上使用的編程語言?ubuntu

什麼是 V8?V8 JavaScript 引擎是 Google 用於其 Chrome 瀏覽器的底層 JavaScript 引擎。不多有人考慮 JavaScript 在客戶機上實際作了些什麼?實際上,JavaScript 引擎負責解釋並執行代碼。Google 使用 V8 建立了一個用 C++ 編寫的超快解釋器,該解釋器擁有另外一個獨特特徵;您能夠下載該引擎並將其嵌入任何 應用程序。V8 JavaScript 引擎並不只限於在一個瀏覽器中運行。所以,Node 實際上會使用 Google 編寫的 V8 JavaScript 引擎,並將其重建爲可在服務器上使用。太完美了!既然已經有一個不錯的解決方案可用,爲什麼還要建立一種新語言呢?瀏覽器

事件驅動編程

許多程序員接受的教育使他們認爲,面向對象編程是完美的編程設計,這使得他們對其餘編程方法不屑一顧。Node 使用了一個所謂的事件驅動編程模型。安全

清單 1. 客戶端上使用 jQuery 的事件驅動編程
1
2
3
4
5
6
7
8
9
// 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 隨機數字生成器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 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 retrives
      // 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 = params.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。下面是服務器已經啓動並運行時看起來的樣子:

1
2
root@ubuntu:/home/moila/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 很是適合如下狀況:在響應客戶端以前,您預計可能有很高的流量,但所需的服務器端邏輯和處理不必定不少。Node 表現出衆的典型示例包括:

  • RESTful API

    提供 RESTful API 的 Web 服務接收幾個參數,解析它們,組合一個響應,並返回一個響應(一般是較少的文本)給用戶。這是適合 Node 的理想狀況,由於您能夠構建它來處理數萬條鏈接。它仍然不須要大量邏輯;它本質上只是從某個數據庫中查找一些值並將它們組成一個響應。因爲響應是少許文本,入站請求也是少許的文本,所以流量不高,一臺機器甚至也能夠處理最繁忙的公司的 API 需求。

  • Twitter 隊列

    想像一下像 Twitter 這樣的公司,它必須接收 tweets 並將其寫入數據庫。實際上,每秒幾乎有數千條 tweet 達到,數據庫不可能及時處理高峯時段所需的寫入數量。Node 成爲這個問題的解決方案的重要一環。如您所見,Node 能處理數萬條入站 tweet。它能快速而又輕鬆地將它們寫入一個內存排隊機制(例如 memcached),另外一個單獨進程能夠從那裏將它們寫入數據庫。Node 在這裏的角色是迅速收集 tweet,並將這個信息傳遞給另外一個負責寫入的進程。想象一下另外一種設計(常規 PHP 服務器會本身嘗試處理對數據庫自己的寫入):每一個 tweet 都會在寫入數據庫時致使一個短暫的延遲,由於數據庫調用正在阻塞通道。因爲數據庫延遲,一臺這樣設計的機器每秒可能只能處理 2000 條入站 tweet。每秒處理 100 萬條 tweet 則須要 500 個服務器。相反,Node 能處理每一個鏈接而不會阻塞通道,從而可以捕獲儘量多的 tweets。一個能處理 50,000 條 tweet 的 Node 機器僅需 20 臺服務器便可。

  • 電子遊戲統計數據

    若是您在線玩過《使命召喚》這款遊戲,當您查看遊戲統計數據時,就會當即意識到一個問題:要生成那種級別的統計數據,必須跟蹤海量信息。這樣,若是有數百萬玩家同時在線玩遊戲,並且他們處於遊戲中的不一樣位置,那麼很快就會生成海量信息。Node 是這種場景的一種很好的解決方案,由於它能採集遊戲生成的數據,對數據進行最少的合併,而後對數據進行排隊,以便將它們寫入數據庫。使用整個服務器來跟蹤玩家在遊戲中發射了多少子彈看起來很愚蠢,若是您使用 Apache 這樣的服務器,可能會 有一些有用的限制;但相反,若是您專門使用一個服務器來跟蹤一個遊戲的全部統計數據,就像使用運行 Node 的服務器所作的那樣,那看起來彷佛是一種明智之舉。

Node 模塊

儘管不是本文最初計劃討論的主題,但應廣大讀者要求,本文已經擴展爲包含一個 Node Modules 和 Node Package Manager 簡介。正如已經習慣使用 Apache 的開發人員那樣,您也能夠經過安裝模塊來擴展 Node 的功能。可是,可用於 Node 的模塊極大地 加強了這個產品,那些模塊很是有用,將使用 Node 的開發人員一般會安裝幾個模塊。所以,模塊也就變得愈來愈重要,甚至成爲整個產品的一個關鍵部分。

在 「參考資料」 部分,我提供了一個指向模塊頁面的連接,該頁面列示了全部可用模塊。爲了展現模塊可以提供的可能性,我在數十個可用模塊中包含了如下幾個模塊:一個用於編寫動態建立的頁面(好比 PHP),一個用於簡化 MySQL 使用,一個用於幫助使用 WebSockets,還有一個用來協助文本和參數解析的模塊。我不會詳細介紹這些模塊,這是由於這篇概述文章旨在幫助您瞭解 Node 並肯定是否須要深刻學習(再次重申),若是須要,那麼您確定有機會用到這些可用模塊。

另外,Node 的一個特性是 Node Package Module,這是一個內置功能,用於安裝和管理 Node 模塊。它自動處理依賴項,所以您能夠肯定:您想要安裝的任何模塊都將正確安裝幷包含必要的依賴項。它還支持將您本身的模塊發佈到 Node 社區,假如您選擇加入社區並編寫本身的模塊的話。您能夠將 NPM 視爲一種容許輕鬆擴展 Node 功能的方法,沒必要擔憂這會破壞您的 Node 安裝。一樣,若是您選擇深刻學習 Node,那麼 NPM 將是您的 Node 解決方案的一個重要組成部分。

結束語

閱讀本文以後,您在本文開頭遇到的問題 「Node.js 到底是什麼東西?」 應該已經獲得瞭解答,您應該能經過幾個清晰簡潔的句子回答這個問題。若是這樣,那麼您已經走到了許多程序員的前面。我和許多人都談論過 Node,但他們對 Node 究竟用於作什麼一直很迷惑。能夠理解,他們具備的是 Apache 的思惟方式,認爲服務器就是一個應用程序,將 HTML 文件放入其中,一切就會正常運轉。因爲大多數程序員都熟悉 Apache 及其用途,所以,描述 Node 的最簡單方法就是將它與 Apache 進行比較。Node 是一個程序,可以完成 Apache 可以完成的全部任務(藉助一些模塊),並且,做爲一個能夠將其做爲基礎進行構建的可擴展 JavaScript 平臺,Node 還能完成更多的任務。

從本文能夠看出,Node 完成了它提供高度可伸縮服務器的目標。它使用了 Google 的一個很是快速的 JavaScript 引擎,即 V8 引擎。它使用一個事件驅動設計來保持代碼最小且易於閱讀。全部這些因素促成了 Node 的理想目標,即編寫一個高度可伸縮的解決方案變得比較容易。

與理解 Node  什麼一樣重要的是,理解它不是 什麼。Node 並不僅是 Apache 的一個替代品,它旨在使 PHP Web 應用程序更容易伸縮。事實遠非如此。儘管 Node 還處於初始階段,但它發展得很是迅速,社區參與度很是高,社區成員建立了大量優秀模塊,一年以內,這個不斷髮展的產品就有可能出如今您的企業中。

相關文章
相關標籤/搜索