- Vue.js+Node.js全棧開發實戰(第2版)
- 王金柱編著
- 5245字
- 2024-12-31 20:25:58
1.1 Node.js基礎
本節將講解Node.js簡介、發展歷史、組織架構、特點以及具體應用等方面的內容。
1.1.1 Node.js簡介
Node.js是基于Google Chrome瀏覽器內置的V8引擎所開發的JavaScript運行時環境。它充分利用了V8引擎的強大性能,借鑒了其很多的前沿技術(例如:GC機制、事件驅動、非阻塞的I/O模型,等等),保證了Node.js的輕量與高效,進而受到了眾多開發者的追捧。
Node.js最顯著的特點就是能夠運行在服務器端(區別于其他腳本語言),以及良好的多平臺兼容性(支持Windows、Linux、Mac OS X、SunOS和FreeBSD等多種系統平臺),使其成為最重要的腳本程序設計語言。
我們都知道,JavaScript腳本語言需要在瀏覽器環境下才可以解釋執行。而Node.js是服務器端的腳本語言,可以直接在后端進行解釋執行。下面就是最基本的Node.js命令執行方法。
node filename.js //node命令直接解釋執行filename.js腳本文件,得到結果
由于Chrome V8引擎執行JavaScript腳本的速度非常快,因此Node.js所開發出來的應用程序性能非常好。Node.js已經成為全棧開發的首選語言之一,并且從它衍生出眾多出色的全棧開發框架。Node.js在全球已經被眾多公司使用,包括創業公司Voxer、Uber,以及知名公司沃爾瑪、微軟等。它們每天通過Node.js處理的請求數以億計,可以說對于要求苛刻的服務器系統來說,Node.js也可以輕松勝任。
Node.js還包括一個完善的社區。在Node.js的官方網站https://nodejs.org/可以找到大量的幫助文檔和示例程序,并且Node.js還有一個強大的npm包管理器。由于其強大的服務端功能,越來越多的人參與到本項目中來,可用的第三方模塊和擴展增長迅猛,而且質量也在不斷提升,Node已是全球較大的開源庫生態系統之一。
提示:Node.js并不是一個JavaScript應用,而是一個JavaScript的運行時環境,其底層由C++語言編寫而成。
1.1.2 Node.js的發展歷史
任何語言或框架都不是一天形成的,而是經過漫長的測試、發布、再測試、再發布的迭代過程,本節將重點介紹一下Node.js的發展歷史。
Node.js的創始人就是大名鼎鼎的Ryan Dahl。Ryan Dahl其實是學數學的,在2008年年末,一個偶然的機會讓他知道了Google推出的全新的Chrome瀏覽器及其V8引擎。而當他了解到,Chrome V8是一個為了實現更快的Web體驗而專門制作的JavaScript引擎時,非常希望能找到一種語言能夠提供先進的推送功能,并集成到自己的網站中去,從而避免采用傳統的不斷輪詢拉取數據的訪問方式。
Ryan Dahl對C/C++和系統調用非常熟悉,他使用系統調用(用C)實現消息推送功能。如果只使用非阻塞式Socket,每個連接的開銷都會非常小。在小規模測試中,它能同時處理幾千個閑置連接,并可以實現相當大的吞吐量。但是,他并不想使用C,他希望能采用另外一種漂亮靈活的動態語言。最初他也想使用Ruby來寫Node.js,但是發現Ruby虛擬機的性能不能滿足要求,后來便嘗試采用V8引擎,所以選擇了C++語言。
2009年2月,Ryan Dahl首次在自己的博客上宣布準備基于V8創建一個輕量級的Web服務器并提供一套庫。2009年5月,他正式在GitHub上發布最初版本的部分Node.js包。隨后幾個月里,有人開始使用Node.js開發應用。實踐證明,JavaScript與非阻塞Socket配合得相當完美,只需要簡單的幾行JavaScript代碼,就可以構建出非常復雜的非阻塞服務器。到了2010年年底,Node.js獲得云計算服務商Joyent的資助。創始人Ryan Dahl加入Joyent,全職負責Node.js的發展。從此以后Node.js迅猛發展,并成為一種流行的開發語言。
在官方網站上,Node.js的版本號是從0.1.14開始的,每個發布版本對應不同的V8引擎版本和npm包管理器版本。截至筆者寫作時,最新的LTS(Long-Term Support,長期支持)版本為V18.17.1。當然,這期間Node.js發生了很曲折的故事,感興趣的讀者可以自行去了解一下。
總結一下,Node.js的發展大致可以分為如下4個階段。
1.發展初期
創始人Ryan Dahl帶著他的團隊開發出以Web為中心的Web.js,此時的一切都非常混亂,API也大多處于試驗階段。
2.快速發展時期
Node.js的核心用戶Isaac Z. Schlueter開發出了奠定Node.js如今地位的重要工具—npm包管理工具。同時,這也是Schlueter未來成為Ryan接班人的重要條件。之后Connect、Express、Socket.io等庫的出現,吸引了一大波愛好者加入Node.js開發者陣營。CoffeeScript的出現更是讓不少Ruby和Python開發者找到了學習的理由。期間,以Node.js作為運行環境的CLI工具涌現出來,其中不乏用于加速前端開發的優秀工具,如Babel、Less、Sass、UglifyJS、Browserify、Grunt、Gulp等。在這個階段,Node.js的發展勢如破竹。
3.不穩定時期
經過了一大批一線工程師的探索實踐后,Node.js開始進入時代的更迭期,新模式代替舊模式,新技術代替舊技術,新實踐代替舊實踐。ECMAScript 6(ECMAScript 2015)也開始出現在Node.js世界中。ECMAScript 6的發展越來越明顯,V8也對ECMAScript 6中的部分特性實現了支持,如Generator等。
4.穩步發展時期
隨著ECMAScript 6的發展和最終定稿,出現了大量利用ECMAScript 6特性開發的新模塊,如原Express核心團隊開發的Koa。Node.js之父Ryan Dahl退出Node.js的核心開發,轉做其他的研究項目。Ryan Dahl的接任者Schlueter負責將Node.js一直開發下去并不斷進行完善。
1.1.3 Node.js組織架構
前面介紹了Node.js是一個完整的JavaScript開發環境,并且是基于Google的Chrome V8引擎進行代碼解釋的。它在設計之初就已經被定位用來解決傳統Web開發語言所遇到的諸多問題,所以Node.js有很多其他開發語言所不具備的優點。下面主要介紹Node.js的組織架構,如圖1.1所示。

圖1.1 Node.js系統架構圖
從圖1.1中可以看到,只有最頂層的Node標準庫(Node standard library)部分是用JavaScript語言編寫的,其余的底層均是用C/C++語言編寫的。
繼續分析圖1.1中描述的Node.js組織架構,關于Node.js的結構大致可以分為以下3個層次。
1.Node.js標準庫
這一層由JavaScript編寫,是在使用過程中能直接調用的API。它在Node.js源代碼中的lib目錄下可以看到,具體包括http、net、stream、fs、buffer、events等模塊。
2.Node bindings
這一層是JavaScript與底層C/C++能夠溝通的關鍵,前者通過bindings調用后者,相互交換數據。
3.Node基礎構件
這一層是支撐Node.js運行的基礎構件,使用C/C++語言編寫,具體包括以下主要模塊。
· V8:Google推出的JavaScript VM,也是Node.js為什么使用JavaScript的關鍵,它為JavaScript提供了在非瀏覽器端運行的環境,它的高性能是Node.js之所以高效的原因之一。
· libuv:為Node.js提供了跨平臺、線程池、事件池、異步I/O等能力,是Node.js如此強大的關鍵。
· C-ares:提供了異步處理DNS相關的能力。
· http_parser、OpenSSL、zlib等:提供了包括HTTP解析、OpenSSL、數據壓縮等功能。
1.1.4 Node.js的特點
Node.js的強大體現在很多方面,如事件驅動、異步處理、非阻塞I/O等。這里將介紹Node.js具備的不同于其他框架的特點,包括事件驅動、異步非阻塞I/O、高性能、單線程等。
1.事件驅動
在某些傳統的網絡編程語言中,都會用到回調函數。比如:當Socket資源達到某種狀態時,注冊的回調函數就會執行。在Node.js的設計思想中,是以事件驅動為核心的,它提供的絕大多數API都是基于事件的、異步的風格。以net模塊為例,其中的net.Socket對象就有connect、data、end、timeout、drain、error、close等事件。使用Node.js的開發人員,需要根據自己的業務邏輯注冊相應的回調函數。這些回調函數都是異步執行的。這意味著雖然在代碼結構中這些函數看起來是依次注冊的,但是它們并不依賴于自身出現的順序,而是等待相應的事件觸發。
事件驅動的優勢在于充分利用了系統資源,執行代碼無須阻塞等待某種操作完成,有限的資源可以用于其他的任務。此類設計非常適合后端的網絡服務編程,Node.js的目標也在于此。在服務器開發中,并發的請求處理是一個大問題,阻塞式的函數會導致資源浪費和時間延遲。通過事件注冊、異步函數,開發人員可以提高資源的利用率,性能也會得到改善。
2.異步非阻塞I/O
從Node.js提供的支持模塊中可以看到,包括文件操作在內的許多函數都是異步執行的,這和傳統語言存在區別。為了方便服務器開發,Node.js的網絡模塊特別多,包括http、dsn、net、udp、https、tls等。開發人員可以在此基礎上快速構建Web服務器應用。一個異步I/O的大致流程如圖1.2所示。

圖1.2 異步I/O的流程
異步I/O流程主要包括以下過程:
(1)發起I/O調用:
① 用戶通過JavaScript代碼調用Node核心模塊,將參數和回調函數傳入核心模塊。
② Node核心模塊會將傳入的參數和回調函數封裝成一個請求對象。
③ 將這個請求對象推入I/O線程池等待執行。
④ JavaScript發起的異步調用結束,JavaScript線程繼續執行后續操作。
(2)執行回調:
① I/O操作完成后會將結果存儲到請求對象的result屬性上,并發出操作完成的通知。
② 每次事件循環時會檢查是否有完成的I/O操作,如果有,就將請求對象加入I/O觀察者隊列中,之后當作事件處理。
③ 處理I/O觀察者事件時,會取出之前封裝在請求對象中的回調函數,執行這個回調函數,并將result當作參數,以實現JavaScript回調的目的。
Node.js的網絡編程非常方便,提供的模塊(在這里是HTTP)開放了容易上手的API接口,短短幾行代碼就可以構建服務器。
3.性能出眾
創始人Ryan Dahl在設計的時候就考慮了性能方面的問題,因此選擇了C++和V8,而不是Ruby或者其他的虛擬機。Node.js在設計上以單進程、單線程模式運行。事件驅動機制是Node.js通過內部單線程高效率地維護事件循環隊列來實現的,沒有多線程的資源占用和上下文切換。這意味著面對大規模的HTTP請求,Node.js是憑借事件驅動來完成的。從大量的測試結果分析來看,Node.js的處理性能非常出色,在QPS(每秒查詢率)達到16 700次時,內存僅占用30MB(測試環境:RHEL 5.2、CPU 2.2GHz、內存4GB)。
4.單線程
Node.js和大名鼎鼎的Nginx一樣,都是以單線程為基礎的。這正是Node.js保持輕量級和高性能的關鍵,也是Ryan Dahl設計Node.js的初衷。這里的單線程是指主線程為“單線程”,所有阻塞的部分交給一個線程池處理,然后這個主線程通過一個隊列跟線程池協作。我們寫的JavaScript代碼部分不用關心線程問題,代碼也主要由一堆回調函數構成,然后主線程在循環過程中適時調用這些代碼。
單線程除了保證Node.js高性能之外,還保證了絕對的線程安全,使開發者不用擔心因為同一變量同時被多個線程讀寫,而造成的程序崩潰。
1.1.5 Node.js應用場景
Node.js可以應用到很多方面,可以說從Node.js開始,開發者就可以使用JavaScript來開發服務器端的程序了。Node.js為前端開發者提供了便利,并在各大網站中承擔重要角色,成為開發高并發大型網絡應用的關鍵技術。Web站點早已不局限于內容的呈現,很多交互型和協作型環境也逐漸被搬到了網站上,而且這種需求還在不斷增長。這就是所謂的數據密集型實時(data-intensive real-time)應用程序,例如在線協作的白板、多人在線游戲等。這種Web應用程序需要一個能夠實時響應大量并發用戶請求的平臺來支撐它們,而這也正是Node.js擅長的領域。此外,Node.js的跨平臺特性也是開發人員選擇使用Node.js語言進行開發的另一大原因。
Node.js的主要應用場景如下:
· JSON APIs:構建一個Rest/JSON API服務,Node.js可以充分發揮其非阻塞I/O模型以及JavaScript對JSON的功能支持(如JSON.stringfy函數)。
· 單頁面、多Ajax請求應用:如Gmail,前端有大量的異步請求,需要服務后端有極高的響應速度。
· 基于Node.js開發UNIX命令行工具:Node.js可以大量生產子進程,并以流的方式輸出,這使得它非常適合用作UNIX命令行工具。
· 流式數據:傳統的Web應用通常會將HTTP請求和響應看作原子事件,而Node.js會充分利用流式數據的這個特點,構建非常酷的應用,如實時文件上傳系統Transloadit。
· 準實時應用系統:如聊天系統、微博系統,但JavaScript是有垃圾回收(GC)機制的,這就意味著系統的響應時間是不平滑的(垃圾回收會導致系統在這一時刻停止工作)。如果想要構建硬實時應用系統,Erlang是一個不錯的選擇。
例如,實時互動交互比較多的社交網站,像Twitter這樣的公司,它必須接收tweets并將其寫入數據庫。實際上,幾乎每秒就有數千條tweets達到,數據庫不可能及時處理高峰時段所需的寫入數量。Node.js成為解決這個問題的重要一環。Node.js能處理數萬條入站tweets。它能快速而又輕松地將它們寫入一個內存排隊機制(例如memcached),而另一個單獨進程可以在那里將它們寫入數據庫。Node.js能處理每個連接而不會阻塞通道,從而能夠捕獲盡可能多的tweets。
雖然看起來Node.js可以做很多事情,并且擁有很高的性能,但是Node.js并不是萬能的,有一些類型的應用Node.js處理起來可能會比較吃力。例如,CPU密集型的應用、模板渲染、壓縮/解壓縮、加/解密等操作都是Node.js的軟肋。
1.1.6 Node.js在國內的發展
在Node.js初期發展的時候,國內就有大量的開發者開始持續關注了。隨著Node.js的不斷成熟,很多國內的公司都開始采用這一新技術。Node.js開發者在國內的數量不斷增加,并涌現出很多組織和機構來自發地進行推廣和技術分享。
國內的各大視頻培訓網站上都有Node.js開發的培訓教程,各大門戶網站也都或多或少地采用了Node.js的開發技術,比如淘寶、網易、百度等有很多項目就運行在Node.js之上。阿里云是這方面比較靠前的公司,它們的云平臺率先支持Node.js的開發。淘寶也為Node.js搭建了國內的NPM鏡像網站,方便國內的開發者下載各種開發包。
以下是關于Node.js中文資源的匯總清單:
(1)Node.js官方網站:該網站是Node.js在國內的官方網站,里面有Node.js最新版本的下載資源和豐富的文檔資料,是Node.js開發愛好者不容錯過的網站。網址為https://nodejs.org/en/。
(2)CNode社區:該社區由一批熱愛Node.js技術的工程師發起,已經吸引了很多互聯網公司的專業技術人員加入,是目前國內非常具有影響力的Node.js開源技術社區。它致力于Node.js的技術研究,擁有論壇,并定期組織一些技術交流活動。網址為https://cnodejs.org。
(3)Node.js中文網:該網站是一個專業的Node.js中文知識分享社區,致力于普及Node.js知識,分享Node.js研究成果,努力推進Node.js在中國的應用和發展。網站中有大量的技術博客和文章,各個級別的開發者都能找到適合自己學習的資料。網址為https://www.nodejs.cn/。
(4)淘寶NPM鏡像:是一個完整npmjs.org鏡像,可以用此代替官方版本,同步頻率為每10分鐘一次,以保證盡量與官方服務同步。網址為https://npm.taobao.org/。
(5)Node.js:這也是一個學習Node.js和前端開發技術非常好的網站,每天都有大量原創文章發布,并且技術問題可以很快被回答。當然,如果你愿意為其他人解答技術問題,或者進行技術分享,也是非常受歡迎的。網址為http://cnodejs.org/。
每年的JavaScript中國開發者大會和各種Node.js分享沙龍,都是很好的學習Node.js開發技術和交流的機會。一個開發者要時刻保持謙虛的心態,并不斷學習最新的技術,這對開發者來說是一種基本能力和素養。