什么是Node.js?Node.js詳細介紹
簡介
如果您聽說過 Node,或者閱讀過一些文章,宣稱 Node 是多么多么的棒,那么您可能會想:“Node 究竟是什么東西?”盡管不是針對所有人的,但 Node 可能是某些人的正確選擇。
為試圖解釋什么是 Node.js,本文探究了它能解決的問題,它如何工作,如何運行一個簡單應用程序,最后,Node 何時是和何時不是一個好的解決方案。本文不涉及如何編寫一個復雜的 Node 應用程序,也不是一份全面的 Node 教程。閱讀本文應該有助于您決定是否應該學習 Node,以便將其用于您的業(yè)務。
Node 旨在解決什么問題?
Node 公開宣稱的目標是 “旨在提供一種簡單的構(gòu)建可伸縮網(wǎng)絡程序的方法”。當前的服務器程序有什么問題?我們來做個數(shù)學題。在 Java™ 和 PHP 這類語言中,每個連接都會生成一個新線程,每個新線程可能需要 2 MB 配套內(nèi)存。在一個擁有 8 GB RAM 的系統(tǒng)上,理論上最大的并發(fā)連接數(shù)量是 4,000 個用戶。隨著您的客戶端基礎的增長,您希望您的 web 應用程序支持更多用戶,這樣,您必須添加更多服務器。當然,這會增加業(yè)務成本,尤其是服務器成本、運輸成本和人工成本。除這些成本上升外,還有一個技術(shù)問題:用戶可能針對每個請求使用不同的服務器,因此,任何共享資源都必須在所有服務器之間共享。例如,在 Java 中,靜態(tài)變量和緩存需要在每個服務器上的 JVMs 之間共享。這就是整個 web 應用程序架構(gòu)中的瓶頸:一個服務器能夠處理的并發(fā)連接的最大數(shù)量。
Node 解決這個問題的方法是:更改連接連接到服務器的方式。每個連接都創(chuàng)建一個進程,該進程不需要配套內(nèi)存塊,而不是為每個連接生成一個新的 OS 線程(并向其分配一些配套內(nèi)存)。Node 聲稱它絕不會死鎖,因為它根本不允許使用鎖,它不會直接阻塞 I/O 調(diào)用。Node 還宣稱,運行它的服務器能支持數(shù)萬個并發(fā)連接。事實上,Node 通過將整個系統(tǒng)中的瓶頸從最大連接數(shù)量更改到單個系統(tǒng)的流量來改變服務器面貌。
現(xiàn)在您有了一個能處理數(shù)萬條并發(fā)連接的程序,那么您能通過 Node 實際構(gòu)建什么呢?如果您有一個 web 應用程序需要處理這么多連接,那將是一件很 “恐怖” 的事!那是一種 “如果您有這個問題,那么它根本不是問題” 的問題。在回答上面的問題之前,我們先看看 Node 如何工作以及它被設計的如何運行。
Node 肯定不是什么
沒錯,Node 是一個服務器程序。但是,它肯定不 像 Apache 或 Tomcat。那些服務器是獨立服務器產(chǎn)品,可以立即安裝并部署應用程序。通過這些產(chǎn)品,您可以在一分鐘內(nèi)啟動并運行一個服務器。Node 肯定不是這種產(chǎn)品。Apache 能添加一個 PHP 模塊來允許開發(fā)人員創(chuàng)建動態(tài) web 頁,使用 Tomcat 的程序員能部署 JSPs 來創(chuàng)建動態(tài) web 頁。Node 肯定不是這種類型。
在 Node 的早期階段(當前是 version 0.4.6),它還不是一個 “運行就緒” 的服務器程序,您還不能安裝它,向其中放置文件,擁有一個功能齊全的 web 服務器。即使是要實現(xiàn) web 服務器在安裝完成后啟動并運行這個基本功能,也還需要做大量工作。
Node 如何工作
Node 本身運行 V8 JavaScript。等等,服務器上的 JavaScript?沒錯,您沒有看錯。服務器端 JavaScript 是一個相對較新的概念,這個概念是大約兩年前在 developerWorks 上討論 Aptana Jaxer 產(chǎn)品時提到的(參見 參考資料)。盡管 Jaxer 一直沒有真正流行,但這個理念本身并不是遙不可及的 — 為何不能在服務器上使用客戶機上使用的編程語言?
什么使 V8?V8 JavaScript 引擎是 Google 用于他們的 Chrome 瀏覽器的底層 JavaScript 引擎。很少有人考慮 JavaScript 在客戶機上實際做了些什么?實際上,JavaScript 引擎負責解釋并執(zhí)行代碼。使用 V8,Google 創(chuàng)建了一個以 C++ 編寫的超快解釋器,該解釋器擁有另一個獨特特征;您可以下載該引擎并將其嵌入任何 應用程序。它不僅限于在一個瀏覽器中運行。因此,Node 實際上使用 Google 編寫的 V8 JavaScript 引擎并將其重建為在服務器上使用。太完美了!既然已經(jīng)有一個不錯的解決方案可用,為何還要創(chuàng)建一種新語言呢?
事件驅(qū)動編程
許多程序員接受的教育使他們認為,面向?qū)ο缶幊淌峭昝赖木幊淘O計,而對其他編程方法不屑一顧。Node 使用一個所謂的事件驅(qū)動編程模型。
清單 1. 客戶端上使用 jQuery 的事件驅(qū)動編程
// 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");
});
實際上,服務器端和客戶端沒有任何區(qū)別。沒錯,這沒有按鈕點擊操作,也沒有向文本字段鍵入的操作,但在一個更高的層面上,事件正在 發(fā)生。一個連接被建立 — 事件!數(shù)據(jù)通過連接接收 — 事件!數(shù)據(jù)通過連接停止 — 事件!
為什么這種設置類型對 Node 很理想?JavaScript 是一種很棒的事件驅(qū)動編程語言,因為它允許匿名函數(shù)和閉包,更重要的是,任何寫過代碼的人都熟悉它的語法。事件發(fā)生時調(diào)用的回調(diào)函數(shù)可以在捕獲事件處編寫。這樣,代碼容易編寫和維護,沒有復雜的面向?qū)ο罂蚣埽瑳]有接口,沒有在上面架構(gòu)任何內(nèi)容的潛能。只需監(jiān)聽事件,編寫一個回調(diào)函數(shù),然后,事件驅(qū)動編程將照管好一切!
示例 Node 應用程序
最后,我們來看一些代碼!讓我們將討論過的所有內(nèi)容綜合起來,創(chuàng)建我們的第一個 Node 應用程序。由于我們已經(jīng)知道,Node 對于處理高流量應用程序很理想,我們就來創(chuàng)建一個非常簡單的 web 應用程序 — 一個為實現(xiàn)最大速度而構(gòu)建的應用程序。下面是 “老板” 交代的關(guān)于我們的樣例應用程序的具體要求:創(chuàng)建一個隨機數(shù)字生成器 RESTful API。這個應用程序應該接受一個輸入:一個名為 “number” 的參數(shù)。然后,應用程序返回一個介于 0 和該參數(shù)之間的隨機數(shù)字,并將生成的數(shù)字返回調(diào)用者。由于 “老板” 希望它成為一個廣泛流行的應用程序,因此它應該能處理 50,000 個并發(fā)用戶。我們來看看代碼:
清單 2. Node 隨機數(shù)字生成器
// 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” 的文件中?,F(xiàn)在,要啟動這個應用程序并運行它(進而創(chuàng)建 HTTP 服務器并監(jiān)聽端口 80 上的連接),只需在您的命令提示中輸入以下命令:% node random.js。下面是服務器已經(jīng)啟動并運行時它看起來的樣子:
root@ubuntu:/home/moila/ws/mike# node random.js
Random Number Generator Running...
訪問應用程序
應用程序已經(jīng)啟動并運行。Node 正在監(jiān)聽任何連接,我們來測試一下。由于我們創(chuàng)建了一個簡單的 RESTful API,我們可以使用我們的 web 瀏覽器來訪問這個應用程序。鍵入以下地址(確保您完成了上面的步驟):http://localhost/?number=27。
您的瀏覽器窗口將更改到一個介于 0 到 27 之間的隨機數(shù)字。單擊瀏覽器上的 “重新載入” 按鈕,將得到另一個隨機數(shù)字。就是這樣,這就是您的第一個 Node 應用程序!
Node 對什么有好處?
到此為止,應該能夠回答 “Node 是什么” 這個問題了,但您可能還不清楚什么時候應該使用它。這是一個需要提出的重要問題,因為 Node 對有一些東西有好處,但相反,對另一些東西而言,目前 Node 可能不是一個好的解決方案。您需要小心決定何時使用 Node,因為在錯誤的情況下使用它可能會導致一個多余編碼的 LOT。
它對什么有好處?
正如您此前所看到的,Node 非常適合以下情況:您預計可能有很高的流量,而在響應客戶端之前服務器端邏輯和處理所需不一定是巨大的。Node 表現(xiàn)出眾的典型示例包括:
1.RESTful API
提供 RESTful API 的 web 服務接收幾個參數(shù),解析它們,組合一個響應,并返回一個響應(通常是較少的文本)給用戶。這是適合 Node 的理想情況,因為您可以構(gòu)建它來處理數(shù)萬條連接。它還不需要大量邏輯;它只是從一個數(shù)據(jù)庫查找一些值并組合一個響應。由于響應是少量文本,入站請求時少量文本,因此流量不高,一臺機器甚至也可以處理最繁忙的公司的 API 需求。
2.Twitter 隊列
想像一下像 Twitter 這樣的公司,它必須接收 tweets 并將其寫入一個數(shù)據(jù)庫。實際上,每秒幾乎有數(shù)千條 tweets 達到,數(shù)據(jù)庫不可能及時處理高峰時段需要的寫入數(shù)量。Node 成為這個問題的解決方案的重要一環(huán)。如您所見,Node 能處理數(shù)萬條入站 tweets。它能迅速輕松地將它們寫入一個內(nèi)存排隊機制(例如 memcached),另一個單獨進程可以從那里將它們寫入數(shù)據(jù)庫。Node 在這里的角色是迅速收集 tweet 并將這個信息傳遞給另一個負責寫入的進程。想象一下另一種設計 — 一個常規(guī) PHP 服務器自己試圖處理對數(shù)據(jù)庫的寫入 — 每個 tweet 將在寫入數(shù)據(jù)庫時導致一個短暫的延遲,這是因為數(shù)據(jù)庫調(diào)用正在阻塞通道。由于數(shù)據(jù)庫延遲,一臺這樣設計的機器每秒可能只能處理 2000 條入站 tweets。每秒 100 萬條 tweets 需要 500 個服務器。相反,Node 能處理每個連接而不會阻塞通道,從而能捕獲盡可能多的 tweets。一個能處理 50,000 條 tweets 的 Node 機器只需要 20 個服務器。
3.映像文件服務器
一個擁有大型分布式網(wǎng)站的公司(比如 Facebook 或 Flickr)可能會決定將所有機器只用于服務映像。Node 將是這個問題的一個不錯的解決方案,因為該公司能使用它編寫一個簡單的文件檢索器,然后處理數(shù)萬條連接。Node 將查找映像文件,返回文件或一個 404 錯誤,然后什么也不用做。這種設置將允許這類分布式網(wǎng)站減少它們服務映像、.js 和 .css 文件等靜態(tài)文件所需的服務器數(shù)量。
它對什么有壞處?
當然,在某些情況下,Node 并非理想選擇。下面是 Node 不擅長的領(lǐng)域:
1.動態(tài)創(chuàng)建的頁
目前,Node 沒有提供一種默認方法來創(chuàng)建動態(tài)頁。例如,使用 JavaServer Pages (JSP) 技術(shù)時,可以創(chuàng)建一個在這樣的 JSP 代碼段中包含循環(huán)的 index.jsp 頁。Node 不支持這類動態(tài)的、HTML 驅(qū)動的頁面。同樣,Node 不太適合作為 Apache 和 Tomcat 這樣的網(wǎng)頁服務器。因此,如果您想在 Node 中提供這樣一個服務器端解決方案,必須自己編寫整個解決方案。PHP 程序員不想在每次部署 web 應用程序時都編寫一個針對 Apache 的 PHP 轉(zhuǎn)換器,當目前為止,這正是 Node 要求您做的。
2. 關(guān)系數(shù)據(jù)庫重型應用程序
Node 的目的是快速、異步和非阻塞。數(shù)據(jù)庫并不一定分享這些目標。它們是同步和阻塞的,因為讀寫時對數(shù)據(jù)庫的調(diào)用在結(jié)果生成之前將一直阻塞通道。因此,一個每個請求都需要大量數(shù)據(jù)庫調(diào)用、大量讀取、大量寫入的 web 應用程序非常不適合 Node,這是因為關(guān)系數(shù)據(jù)庫本身就能抵銷 Node 的眾多優(yōu)勢。(新的 NoSQL 數(shù)據(jù)庫更適合 Node,不過那完全是另一個主題了。)
結(jié)束語
問題是 “什么是 Node.js?” 應該已經(jīng)得到解答。閱讀本文之后,您應該能通過幾個清晰簡潔的句子回答這個問題。如果這樣,那么您已經(jīng)走到了許多編碼員和程序員的前面。我和許多人都談論過 Node,但它們對 Node 究竟是什么一直很迷惑??梢岳斫猓麄兙哂械氖?Apache 的思維方式 — 服務器是一個應用程序,將 HTML 文件放入其中,一切就會正常運轉(zhuǎn)。而 Node 是目的驅(qū)動的。它是一個軟件程序,使用 JavaScript 來允許程序員輕松快速地創(chuàng)建快速、可伸縮的 web 服務器。Apache 是運行就緒的,而 Node 是編碼就緒的。
Node 完成了它提供高度可伸縮服務器的目標。它并不分配一個 “每個連接一個線程” 模型,而是使用一個 “每個連接一個流程” 模型,只創(chuàng)建每個連接需要的內(nèi)存。它使用 Google 的一個非??焖俚?JavaScript 引擎:V8 引擎。它使用一個事件驅(qū)動設計來保持代碼最小且易于閱讀。所有這些因素促成了 Node 的理想目標 — 編寫一個高度可伸縮的解決方案變得比較容易。
與理解 Node 是 什么同樣重要的是,理解它不是 什么。Node 并不是 Apache 的一個替代品,后者旨在使 PHP web 應用程序更容易伸縮。事實確實如此。在 Node 的這個初始階段,大量程序員使用它的可能性不大,但在它能發(fā)揮作用的場景中,它的表現(xiàn)非常好。
將來應該期望從 Node 得到什么呢?這也許是本文引出的最重要的問題。既然您知道了它現(xiàn)在的作用,您應該會想知道它下一步將做什么。在接下來的一年中,我期待著 Node 提供與現(xiàn)有的第三方支持庫更好地集成。現(xiàn)在,許多第三方程序員已經(jīng)研發(fā)了用于 Node 的插件,包括添加文件服務器支持和 MySQL 支持。希望 Node 開始將它們集成到其核心功能中。最后,我還希望 Node 支持某種動態(tài)頁面模塊,這樣,您就可以在 HTML 文件中執(zhí)行在 PHP 和 JSP(也許是一個 NSP,一個 Node 服務器頁)中所做的操作。最后,希望有一天會出現(xiàn)一個 “部署就緒” 的 Node 服務器,可以下載和安裝,只需將您的 HTML 文件放到其中,就像使用 Apache 或 Tomcat 那樣。Node 現(xiàn)在還處于初始階段,但它發(fā)展得很快,可能不久就會出現(xiàn)在您的視野中。
相關(guān)文章
NodeJs crypto加密制作token的實現(xiàn)代碼
這篇文章主要介紹了NodeJs crypto加密制作token的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-11-11node.js中使用q.js實現(xiàn)api的promise化
這篇文章主要介紹了node.js中使用q.js實現(xiàn)api的promise化,promise一個標準,它描述了異步調(diào)用的返回結(jié)果,包括正確返回結(jié)果和錯誤處理,需要的朋友可以參考下2014-09-09Node.JS 循環(huán)遞歸復制文件夾目錄及其子文件夾下的所有文件
在Node.js中,要實現(xiàn)目錄文件夾的循環(huán)遞歸復制也非常簡單,使用fs模塊即可,僅需幾行,而且性能也不錯,我們先來實現(xiàn)文件的復制,需要的朋友可以參考下2017-09-09