究竟什么是Node.js?Node.js有什么好處?
Node 是一個(gè)服務(wù)器端 JavaScript 解釋器,它將改變服務(wù)器應(yīng)該如何工作的概念。它的目標(biāo)是幫助程序員構(gòu)建高度可伸縮的應(yīng)用程序,編寫能夠處理數(shù)萬條同時(shí)連接到一個(gè)(只有一個(gè))物理機(jī)的連接代碼。
簡(jiǎn)介
如果您聽說過 Node,或者閱讀過一些文章,宣稱 Node 是多么多么的棒,那么您可能會(huì)想:“Node 究竟是什么東西?” 即便是在參閱 Node 的主頁之后,您甚至可能還是 不明白 Node 為何物?Node 肯定不適合每個(gè)程序員,但它可能是某些程序員一直苦苦追尋的東西。
為試圖解釋什么是 Node.js,本文將簡(jiǎn)要介紹一些背景信息:它要解決的問題,它如何工作,如何運(yùn)行一個(gè)簡(jiǎn)單應(yīng)用程序,最后,Node 在什么情況下是一個(gè)好的解決方案。本文不涉及如何編寫一個(gè)復(fù)雜的 Node 應(yīng)用程序,也不是一份全面的 Node 教程。閱讀本文應(yīng)該有助于您決定是否應(yīng)該繼續(xù)學(xué)習(xí) Node,以便將其用于您的業(yè)務(wù)。
Node 旨在解決什么問題?
Node 公開宣稱的目標(biāo)是 “旨在提供一種簡(jiǎn)單的構(gòu)建可伸縮網(wǎng)絡(luò)程序的方法”。當(dāng)前的服務(wù)器程序有什么問題?我們來做個(gè)數(shù)學(xué)題。在 Java™ 和 PHP 這類語言中,每個(gè)連接都會(huì)生成一個(gè)新線程,每個(gè)新線程可能需要 2 MB 的配套內(nèi)存。在一個(gè)擁有 8 GB RAM 的系統(tǒng)上,理論上最大的并發(fā)連接數(shù)量是 4,000 個(gè)用戶。隨著您的客戶群的增長(zhǎng),如果希望您的 Web 應(yīng)用程序支持更多用戶,那么,您必須添加更多服務(wù)器。當(dāng)然,這會(huì)增加服務(wù)器成本、流量成本和人工成本等成本。除這些成本上升外,還有一個(gè)潛在技術(shù)問題,即用戶可能針對(duì)每個(gè)請(qǐng)求使用不同的服務(wù)器,因此,任何共享資源都必須在所有服務(wù)器之間共享。鑒于上述所有原因,整個(gè) Web 應(yīng)用程序架構(gòu)(包括流量、處理器速度和內(nèi)存速度)中的瓶頸是:服務(wù)器能夠處理的并發(fā)連接的最大數(shù)量。
Node 解決這個(gè)問題的方法是:更改連接到服務(wù)器的方式。每個(gè)連接發(fā)射一個(gè)在 Node 引擎的進(jìn)程中運(yùn)行的事件,而不是為每個(gè)連接生成一個(gè)新的 OS 線程(并為其分配一些配套內(nèi)存)。Node 聲稱它絕不會(huì)死鎖,因?yàn)樗静辉试S使用鎖,它不會(huì)直接阻塞 I/O 調(diào)用。Node 還宣稱,運(yùn)行它的服務(wù)器能支持?jǐn)?shù)萬個(gè)并發(fā)連接。
現(xiàn)在您有了一個(gè)能處理數(shù)萬個(gè)并發(fā)連接的程序,那么您能通過 Node 實(shí)際構(gòu)建什么呢?如果您有一個(gè) Web 應(yīng)用程序需要處理這么多連接,那將是一件很 “恐怖” 的事!那是一種 “如果您有這個(gè)問題,那么它根本不是問題” 的問題。在回答上面的問題之前,我們先看看 Node 的工作原理以及它的設(shè)計(jì)運(yùn)行方式。
Node 肯定不是什么?
沒錯(cuò),Node 是一個(gè)服務(wù)器程序。但是,基礎(chǔ) Node 產(chǎn)品肯定不 像 Apache 或 Tomcat。本質(zhì)上,那些服務(wù)器 “安裝就緒型” 服 務(wù)器產(chǎn)品,支持立即部署應(yīng)用程序。通過這些產(chǎn)品,您可以在一分鐘內(nèi)啟動(dòng)并運(yùn)行一個(gè)服務(wù)器。Node 肯定不是這種產(chǎn)品。Apache 能通過添加一個(gè) PHP 模塊來允許開發(fā)人員創(chuàng)建動(dòng)態(tài) Web 頁,添加一個(gè) SSL 模塊來實(shí)現(xiàn)安全連接,與此類似,Node 也有模塊概念,允許向 Node 內(nèi)核添加模塊。實(shí)際上,可供選擇的用于 Node 的模塊有數(shù)百個(gè)之多,社區(qū)在創(chuàng)建、發(fā)布和更新模塊方面非?;钴S,一天甚至可以處理數(shù)十個(gè)模塊。本文后面將討論 Node 的整個(gè)模塊部分。
Node 如何工作?
Node 本身運(yùn)行 V8 JavaScript。等等,服務(wù)器上的 JavaScript?沒錯(cuò),您沒有看錯(cuò)。對(duì)于只在客戶機(jī)上使用 JavaScript 的程序員而言,服務(wù)器端 JavaScript 可能是一個(gè)新概念,但這個(gè)概念本身并非遙不可及,因此為何不能在服務(wù)器上使用客戶機(jī)上使用的編程語言?
什么是 V8?V8 JavaScript 引擎是 Google 用于其 Chrome 瀏覽器的底層 JavaScript 引擎。很少有人考慮 JavaScript 在客戶機(jī)上實(shí)際做了些什么?實(shí)際上,JavaScript 引擎負(fù)責(zé)解釋并執(zhí)行代碼。Google 使用 V8 創(chuàng)建了一個(gè)用 C++ 編寫的超快解釋器,該解釋器擁有另一個(gè)獨(dú)特特征;您可以下載該引擎并將其嵌入任何 應(yīng)用程序。V8 JavaScript 引擎并不僅限于在一個(gè)瀏覽器中運(yùn)行。因此,Node 實(shí)際上會(huì)使用 Google 編寫的 V8 JavaScript 引擎,并將其重建為可在服務(wù)器上使用。太完美了!既然已經(jīng)有一個(gè)不錯(cuò)的解決方案可用,為何還要?jiǎng)?chuàng)建一種新語言呢?
事件驅(qū)動(dòng)編程
許多程序員接受的教育使他們認(rèn)為,面向?qū)ο缶幊淌峭昝赖木幊淘O(shè)計(jì),這使得他們對(duì)其他編程方法不屑一顧。Node 使用了一個(gè)所謂的事件驅(qū)動(dòng)編程模型。
清單 1. 客戶端上使用 jQuery 的事件驅(qū)動(dòng)編程
// 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");
});
實(shí)際上,服務(wù)器端和客戶端沒有任何區(qū)別。沒錯(cuò),這沒有按鈕點(diǎn)擊操作,也沒有向文本字段鍵入的操作,但在一個(gè)更高的層面上,事件正在 發(fā)生。一個(gè)連接被建立,這是一個(gè)事件!數(shù)據(jù)通過連接進(jìn)行接收,這也是一個(gè)事件!數(shù)據(jù)通過連接停止,這還是一個(gè)事件!
為什么這種設(shè)置類型對(duì) Node 很理想?JavaScript 是一種很棒的事件驅(qū)動(dòng)編程語言,因?yàn)樗试S使用匿名函數(shù)和閉包,更重要的是,任何寫過代碼的人都熟悉它的語法。事件發(fā)生時(shí)調(diào)用的回調(diào)函數(shù)可以在捕獲事件處進(jìn)行編寫。這樣可以使代碼容易編寫和維護(hù),沒有復(fù)雜的面向?qū)ο罂蚣?,沒有接口,沒有過度設(shè)計(jì)的可能性。只需監(jiān)聽事件,編寫一個(gè)回調(diào)函數(shù),其他事情都可以交給系統(tǒng)處理!
示例 Node 應(yīng)用程序
最后,我們來看一些代碼!讓我們將討論過的所有內(nèi)容匯總起來,從而創(chuàng)建我們的第一個(gè) Node 應(yīng)用程序。我們已經(jīng)知道,Node 對(duì)于處理高流量應(yīng)用程序很理想,所以我們將創(chuàng)建一個(gè)非常簡(jiǎn)單的 Web 應(yīng)用程序,一個(gè)為實(shí)現(xiàn)最快速度而構(gòu)建的應(yīng)用程序。下面是 “老板” 交代的關(guān)于我們的樣例應(yīng)用程序的具體要求:創(chuàng)建一個(gè)隨機(jī)數(shù)字生成器 RESTful API。這個(gè)應(yīng)用程序應(yīng)該接受一個(gè)輸入:一個(gè)名為 “number” 的參數(shù)。然后,應(yīng)用程序返回一個(gè)介于 0 和該參數(shù)之間的隨機(jī)數(shù)字,并將生成的數(shù)字返回給調(diào)用者。由于 “老板” 希望該應(yīng)用程序成為一個(gè)廣泛流行的應(yīng)用程序,因此它應(yīng)該能處理 50,000 個(gè)并發(fā)用戶。我們來看看以下代碼:
清單 2. Node 隨機(jī)數(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...");
啟動(dòng)應(yīng)用程序
將上面的代碼放入一個(gè)名為 “random.js” 的文件中。現(xiàn)在,要啟動(dòng)這個(gè)應(yīng)用程序并運(yùn)行它(以便創(chuàng)建 HTTP 服務(wù)器并監(jiān)聽端口 80 上的連接),只需在您的命令提示中輸入以下命令:% node random.js。下面是服務(wù)器已經(jīng)啟動(dòng)并運(yùn)行時(shí)看起來的樣子:
root@ubuntu:/home/moila/ws/mike# node random.js
Random Number Generator Running...
訪問應(yīng)用程序
應(yīng)用程序已經(jīng)啟動(dòng)并運(yùn)行。Node 正在監(jiān)聽所有連接,我們來測(cè)試一下。由于我們創(chuàng)建了一個(gè)簡(jiǎn)單的 RESTful API,所以可以使用 Web 瀏覽器來訪問這個(gè)應(yīng)用程序。鍵入以下地址(確保您已完成了上面的步驟):http://localhost/?number=27。
您的瀏覽器窗口將更改到一個(gè)介于 0 到 27 之間的隨機(jī)數(shù)字。單擊瀏覽器上的 “重新載入” 按鈕,您會(huì)得到另一個(gè)隨機(jī)數(shù)字。就是這樣,這就是您的第一個(gè) Node 應(yīng)用程序!
Node 對(duì)什么有好處?
到此為止,您可能能夠回答 “Node 是什么” 這個(gè)問題了,但您可能還有一個(gè)問題:“Node 有什么用途?” 這是一個(gè)需要提出的重要問題,因?yàn)榭隙ㄓ行〇|西能受益于 Node。
它對(duì)什么有好處?
正如您此前所看到的,Node 非常適合以下情況:在響應(yīng)客戶端之前,您預(yù)計(jì)可能有很高的流量,但所需的服務(wù)器端邏輯和處理不一定很多。Node 表現(xiàn)出眾的典型示例包括:
RESTful API
提供 RESTful API 的 Web 服務(wù)接收幾個(gè)參數(shù),解析它們,組合一個(gè)響應(yīng),并返回一個(gè)響應(yīng)(通常是較少的文本)給用戶。這是適合 Node 的理想情況,因?yàn)槟梢詷?gòu)建它來處理數(shù)萬條連接。它仍然不需要大量邏輯;它本質(zhì)上只是從某個(gè)數(shù)據(jù)庫中查找一些值并將它們組成一個(gè)響應(yīng)。由于響應(yīng)是少量文本,入站請(qǐng)求也是少量的文本,因此流量不高,一臺(tái)機(jī)器甚至也可以處理最繁忙的公司的 API 需求。
Twitter 隊(duì)列
想像一下像 Twitter 這樣的公司,它必須接收 tweets 并將其寫入數(shù)據(jù)庫。實(shí)際上,每秒幾乎有數(shù)千條 tweet 達(dá)到,數(shù)據(jù)庫不可能及時(shí)處理高峰時(shí)段所需的寫入數(shù)量。Node 成為這個(gè)問題的解決方案的重要一環(huán)。如您所見,Node 能處理數(shù)萬條入站 tweet。它能快速而又輕松地將它們寫入一個(gè)內(nèi)存排隊(duì)機(jī)制(例如 memcached),另一個(gè)單獨(dú)進(jìn)程可以從那里將它們寫入數(shù)據(jù)庫。Node 在這里的角色是迅速收集 tweet,并將這個(gè)信息傳遞給另一個(gè)負(fù)責(zé)寫入的進(jìn)程。想象一下另一種設(shè)計(jì)(常規(guī) PHP 服務(wù)器會(huì)自己嘗試處理對(duì)數(shù)據(jù)庫本身的寫入):每個(gè) tweet 都會(huì)在寫入數(shù)據(jù)庫時(shí)導(dǎo)致一個(gè)短暫的延遲,因?yàn)閿?shù)據(jù)庫調(diào)用正在阻塞通道。由于數(shù)據(jù)庫延遲,一臺(tái)這樣設(shè)計(jì)的機(jī)器每秒可能只能處理 2000 條入站 tweet。每秒處理 100 萬條 tweet 則需要 500 個(gè)服務(wù)器。相反,Node 能處理每個(gè)連接而不會(huì)阻塞通道,從而能夠捕獲盡可能多的 tweets。一個(gè)能處理 50,000 條 tweet 的 Node 機(jī)器僅需 20 臺(tái)服務(wù)器即可。
電子游戲統(tǒng)計(jì)數(shù)據(jù)
如果您在線玩過《使命召喚》這款游戲,當(dāng)您查看游戲統(tǒng)計(jì)數(shù)據(jù)時(shí),就會(huì)立即意識(shí)到一個(gè)問題:要生成那種級(jí)別的統(tǒng)計(jì)數(shù)據(jù),必須跟蹤海量信息。這樣,如果有數(shù)百萬玩家同時(shí)在線玩游戲,而且他們處于游戲中的不同位置,那么很快就會(huì)生成海量信息。Node 是這種場(chǎng)景的一種很好的解決方案,因?yàn)樗懿杉螒蛏傻臄?shù)據(jù),對(duì)數(shù)據(jù)進(jìn)行最少的合并,然后對(duì)數(shù)據(jù)進(jìn)行排隊(duì),以便將它們寫入數(shù)據(jù)庫。使用整個(gè)服務(wù)器來跟蹤玩家在游戲中發(fā)射了多少子彈看起來很愚蠢,如果您使用 Apache 這樣的服務(wù)器,可能會(huì) 有一些有用的限制;但相反,如果您專門使用一個(gè)服務(wù)器來跟蹤一個(gè)游戲的所有統(tǒng)計(jì)數(shù)據(jù),就像使用運(yùn)行 Node 的服務(wù)器所做的那樣,那看起來似乎是一種明智之舉。
Node 模塊
盡管不是本文最初計(jì)劃討論的主題,但應(yīng)廣大讀者要求,本文已經(jīng)擴(kuò)展為包含一個(gè) Node Modules 和 Node Package Manager 簡(jiǎn)介。正如已經(jīng)習(xí)慣使用 Apache 的開發(fā)人員那樣,您也可以通過安裝模塊來擴(kuò)展 Node 的功能。但是,可用于 Node 的模塊極大地 增強(qiáng)了這個(gè)產(chǎn)品,那些模塊非常有用,將使用 Node 的開發(fā)人員通常會(huì)安裝幾個(gè)模塊。因此,模塊也就變得越來越重要,甚至成為整個(gè)產(chǎn)品的一個(gè)關(guān)鍵部分。
在 “參考資料” 部分,我提供了一個(gè)指向模塊頁面的鏈接,該頁面列示了所有可用模塊。為了展示模塊能夠提供的可能性,我在數(shù)十個(gè)可用模塊中包含了以下幾個(gè)模塊:一個(gè)用于編寫動(dòng)態(tài)創(chuàng)建的頁面(比如 PHP),一個(gè)用于簡(jiǎn)化 MySQL 使用,一個(gè)用于幫助使用 WebSockets,還有一個(gè)用來協(xié)助文本和參數(shù)解析的模塊。我不會(huì)詳細(xì)介紹這些模塊,這是因?yàn)檫@篇概述文章旨在幫助您了解 Node 并確定是否需要深入學(xué)習(xí)(再次重申),如果需要,那么您肯定有機(jī)會(huì)用到這些可用模塊。
另外,Node 的一個(gè)特性是 Node Package Module,這是一個(gè)內(nèi)置功能,用于安裝和管理 Node 模塊。它自動(dòng)處理依賴項(xiàng),因此您可以確定:您想要安裝的任何模塊都將正確安裝并包含必要的依賴項(xiàng)。它還支持將您自己的模塊發(fā)布到 Node 社區(qū),假如您選擇加入社區(qū)并編寫自己的模塊的話。您可以將 NPM 視為一種允許輕松擴(kuò)展 Node 功能的方法,不必?fù)?dān)心這會(huì)破壞您的 Node 安裝。同樣,如果您選擇深入學(xué)習(xí) Node,那么 NPM 將是您的 Node 解決方案的一個(gè)重要組成部分。
結(jié)束語
閱讀本文之后,您在本文開頭遇到的問題 “Node.js 究竟是什么東西?” 應(yīng)該已經(jīng)得到了解答,您應(yīng)該能通過幾個(gè)清晰簡(jiǎn)潔的句子回答這個(gè)問題。如果這樣,那么您已經(jīng)走到了許多程序員的前面。我和許多人都談?wù)撨^ Node,但他們對(duì) Node 究竟用于做什么一直很迷惑??梢岳斫?,他們具有的是 Apache 的思維方式,認(rèn)為服務(wù)器就是一個(gè)應(yīng)用程序,將 HTML 文件放入其中,一切就會(huì)正常運(yùn)轉(zhuǎn)。由于大多數(shù)程序員都熟悉 Apache 及其用途,因此,描述 Node 的最簡(jiǎn)單方法就是將它與 Apache 進(jìn)行比較。Node 是一個(gè)程序,能夠完成 Apache 能夠完成的所有任務(wù)(借助一些模塊),而且,作為一個(gè)可以將其作為基礎(chǔ)進(jìn)行構(gòu)建的可擴(kuò)展 JavaScript 平臺(tái),Node 還能完成更多的任務(wù)。
從本文可以看出,Node 完成了它提供高度可伸縮服務(wù)器的目標(biāo)。它使用了 Google 的一個(gè)非常快速的 JavaScript 引擎,即 V8 引擎。它使用一個(gè)事件驅(qū)動(dòng)設(shè)計(jì)來保持代碼最小且易于閱讀。所有這些因素促成了 Node 的理想目標(biāo),即編寫一個(gè)高度可伸縮的解決方案變得比較容易。
與理解 Node 是 什么同樣重要的是,理解它不是 什么。Node 并不只是 Apache 的一個(gè)替代品,它旨在使 PHP Web 應(yīng)用程序更容易伸縮。事實(shí)遠(yuǎn)非如此。盡管 Node 還處于初始階段,但它發(fā)展得非常迅速,社區(qū)參與度非常高,社區(qū)成員創(chuàng)建了大量?jī)?yōu)秀模塊,一年之內(nèi),這個(gè)不斷發(fā)展的產(chǎn)品就有可能出現(xiàn)在您的企業(yè)中。
相關(guān)文章
NodeJS?基于?Dapr?構(gòu)建云原生微服務(wù)應(yīng)用快速入門教程
Dapr?是一個(gè)可移植的、事件驅(qū)動(dòng)的運(yùn)行時(shí),它使任何開發(fā)人員能夠輕松構(gòu)建出彈性的、無狀態(tài)和有狀態(tài)的應(yīng)用程序,并可運(yùn)行在云平臺(tái)或邊緣計(jì)算中,它同時(shí)也支持多種編程語言和開發(fā)框架,本文重點(diǎn)介紹NodeJS云原生微服務(wù)應(yīng)用,感興趣的朋友一起看看吧2022-07-07NodeJS實(shí)現(xiàn)視頻轉(zhuǎn)碼的示例代碼
本篇文章主要介紹了NodeJS實(shí)現(xiàn)視頻轉(zhuǎn)碼的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11