Node.js | 入門簡介
前言
三不五時常聽到人家在討論技術或是看文章總是會提到Node.js
,對!就是聽到,但心中總是出現疑問,是「3小」~。
所以決定認認真真地去瞭解一下這門語言?技術?
首先看Node.js
,是已經了解JavaScript
基本「使用」的工程師來做學習會比較好上手,而有Server
端經驗的當然就更好啦。
後面在學習過程中,會加入自己的理解方式還有比喻來幫助學習!對於自己的理解、比喻、觀念未必絕對正確!
JavaScript與你
拋開技術,我們先來聊聊你以及你和JavaScript
的關系。
如果你和我一樣,那麼你很早就開始利用HTML
進行「開發」,正因如此,你接觸到了這個叫JavaScript
有趣的東西,而對於JavaScript
,你只會基本的操作——為web
頁面增加互動。
而你真正想要的是「實用的東西」,你想要知道如何建構複雜的Web
站台,於是,你學習了諸如PHP
、Ruby
、Java
這樣的程式語言,並開始書寫「後端」程式。
與此同時,你還始終關注著JavaScript
,隨著透過一些對jQuery
,Prototype
之類技術的介紹,你慢慢了解到了很多JavaScript
中的進階技能,同時也感受到了JavaScript
絕非僅僅是window.open()
那麼簡單。
不過,這些畢竟都是前端技術,盡管當想要增強頁面的時候,使用jQuery
總讓你覺得很爽,但到最後,你頂多是個JavaScript
用戶,而非JavaScript
開發者。
於是,你覺得是時候該重新拾起既熟悉又陌生的JavaScript了
。但是別急,寫Node.js
應用是一件事情;理解為什麼它們要以它們書寫的這種方式來書寫則意味著——你要懂JavaScript
。
問題來了:
由於JavaScript
真正意義上以兩種,甚至可以說是三種形態存在(從中世紀90年代的作為對DHTML
進行增強的小玩具,到像jQuery
那樣嚴格意義上的前端技術,一直到現在的伺服器端技術),因此,很難找到一個正確的方式來學習JavaScript
,使得讓你書寫Node.js
應用的時候感覺自己是在真正開發它而不僅僅是使用它。
因為這就是關鍵:
你本身已經是個有經驗的開發者,你不想透過到處尋找各種解決方案(其中可能還有不正確的)來學習新的技術,你要確保自己是透過正確的方式來學習這項技術。
伺服器端JavaScript (Node.js)
Node.js
是什麼呢?根據官網的說法:
1 | Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. |
「runtime
」 指的是執行環境,就如同網頁上的JavaScript
是在瀏覽器的JavaScript
引擎上執行,Node.js
就是一個能執行 JavaScript
的環境,而V8
則是主流瀏覽器 - Google Chrome
的JavaScript
引擎,負責解析、執行JavaScript
,也就是負責實踐 ECMAScript
規範中定義的部份;另外,V8
是開源的專案,有興趣的讀者可以參照Google Git - V8
。
Node.js
以V8
為核心,加上一系列C/C++
的套件,成功的讓Server
端也可以執行JavaScript
。
JavaScript
最早是運行在瀏覽器中,然而瀏覽器只是提供了一個上下文,它定義了使用JavaScript
可以做什麼,但並沒有說太多關於JavaScript
語言本身可以做什麼。事實上,JavaScript
是一門完整的語言:它可以使用在不同的上下文中,其能力與其他同類語言相比有過之而無不及。
Node.js
事實上就是另外一種上下文,它允許在後端(脫離瀏覽器環境)運行JavaScript
程式。
要實現在後台運行JavaScript
程式,程式需要先被解釋然後正確的執行。Node.js
的原理正是如此,它使用了Google
的V8
虛擬機,來解釋和執行JavaScript
程式。
除此之外,伴隨著Node.js
的還有許多有用的模組,它們可以簡化很多重復的勞作,比如向終端輸出字串。
因此,Node.js
事實上既是一個運行時環境,同時又是一個函式庫。
優點
但是,後端語言已經這麼多了,為什麼還要大費周章的將JavaScript
移植到Server
端呢?
這是因為JavaScript
是一個事件驅動的語言,透過事件迴圈,能讓執行緒幾乎不會被卡住;而這樣的特性,非常適合用來接收高併發(High Concurrency
)的請求。
例如在傳統的伺服器中,每個使用者的連接都會產生一個新的執行緒(看實作,不一定),並佔據一定的效能,伺服器在高併發的情況下,很容易就會由於應接不暇而無法服務新的流量;但Node.js
會將每個request
變成事件迴圈中待處理的事件,主執行緒只負責承接、轉拋、回應,並持續的在事件迴圈中循環,一切都以事件為核心在驅動程式運行,自然也就不會出現執行緒卡死的現象。
當然,如果是商業邏輯複雜的後端程式,效能瓶頸不在流量的服務,Node.js
就無用武之地;但在設計需要承接高流量,且處理邏輯不太複雜時,Node.js
可能就會是個可以考慮的選項。
功能
前面提到,Node.js
就是一個可以執行JavaScript
的環境,而這個環境除了提供瀏覽器Web API
實作的setTimeout
、setInterval
、console
之外,也因為執行環境不同,有另外一系列的API
供開發者使用,例如可以讀寫檔案的fs
、處理網路請求的http
、做加解密雜湊處理的crypto
、設定叢集的cluster
等等。
詳細的使用說明,可以參考Node.js 的官網文件
比喻:首先我所了解的是
JavaScript
基本上都是在瀏覽器上面執行,而Node.js
就是建立一個可以執行JavaScript
的環境;這是什麼意思?如果拿JDK比喻,應該比較容易了解。Java是透過JDK編譯、執行。而JavaScript
不透過瀏覽器,也想要這樣編譯、執行,Node.js
就是提供這樣的環境(脫離瀏覽器環境)~(有錯勿鞭)。
事件迴圈
由於JavaScript
擁有單執行緒的特性,且為了讓執行緒不會被需要等待的同步程式卡住,必須透過事件迴圈的機制來實現這個目標。
瀏覽器中JavaScript
的事件迴圈,可以參考此篇文章,其中有很大一部分是由瀏覽器完成的。Node.js
中則透過libuv
來實現這部分的機制。不同於瀏覽器的事件迴圈,Node.js
中的事件迴圈大致會有以下幾個階段:
名稱 | 說明 |
---|---|
timers | 執行 setTimeout setInterval 給的 callback |
pending callbacks | 執行被延遲到下一個事件迴圈的 I/O Callback |
idle, prepare | Node.js 內部專用的階段 |
poll | 檢索新的 I/O events,執行 I/O callbacks |
check | 執行 setImmediate 給的 callback。 |
close callbacks | 執行關閉資源的 callback,例如 socket.on(‘close’, …) |
相對於瀏覽器的事件迴圈多了好多個階段,但其實只是把所有的callback
分成了四種:timers
、I/O events
、immediates
、close handlers
,並依照順序輪流執行,其他在概念上還是一樣的:每個階段有自己的Queue
,輪到它時清空Queue
,到下個階段,周而復始。
為避免主執行緒阻塞,poll
階段可以設定執行上限,到達上限時就會將Queue
內的東西移交到pending callbacks
階段的Queue
中,下一個事件迴圈時再接續執行。
比較需要注意的地方是,微任務佇列(microtask queue
)在每個階段結束後都會執行、清空,順序是先清空process.nextTick
的 callback
,再執行其他的如Promise
的callback
。
常有人誤解process.nextTick
,會想問例如「一個Tick
是多久?」之類的問題,但其實Tick
指的就是事件迴圈中的一個階段,因此時間是不固定的喔!
結語
Node.js
在上述中絕對是不只這些的,這邊只有整理一些基本的概念,還有很多東西沒有特別提到,提太多你也不想學了(我就是…哈);如果看不懂或是不了解,別著急。先看過知道有這東西,後面慢慢學習一步一腳印慢慢理解,最後必然突然開竅。
註:以上參考了
Node.js 是什麼?跟 JavaScript 有什麼關係
Node入門
狼叔:如何正确的学习Node.js