Like Share Discussion Bookmark Smile

J.J. Huang   2020-01-13   Node.js   瀏覽次數:

Node.js | 入門簡介

前言

三不五時常聽到人家在討論技術或是看文章總是會提到Node.js,對!就是聽到,但心中總是出現疑問,是「3小」~。
所以決定認認真真地去瞭解一下這門語言?技術?

首先看Node.js,是已經了解JavaScript基本「使用」的工程師來做學習會比較好上手,而有Server端經驗的當然就更好啦。
後面在學習過程中,會加入自己的理解方式還有比喻來幫助學習!對於自己的理解、比喻、觀念未必絕對正確

JavaScript與你

拋開技術,我們先來聊聊你以及你和JavaScript的關系。

如果你和我一樣,那麼你很早就開始利用HTML進行「開發」,正因如此,你接觸到了這個叫JavaScript有趣的東西,而對於JavaScript,你只會基本的操作——為web頁面增加互動。

而你真正想要的是「實用的東西」,你想要知道如何建構複雜的Web站台,於是,你學習了諸如PHPRubyJava這樣的程式語言,並開始書寫「後端」程式。

與此同時,你還始終關注著JavaScript,隨著透過一些對jQueryPrototype之類技術的介紹,你慢慢了解到了很多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 ChromeJavaScript引擎,負責解析、執行JavaScript,也就是負責實踐 ECMAScript規範中定義的部份;另外,V8是開源的專案,有興趣的讀者可以參照Google Git - V8

Node.jsV8為核心,加上一系列C/C++的套件,成功的讓Server端也可以執行JavaScript

JavaScript最早是運行在瀏覽器中,然而瀏覽器只是提供了一個上下文,它定義了使用JavaScript可以做什麼,但並沒有說太多關於JavaScript語言本身可以做什麼。事實上,JavaScript是一門完整的語言:它可以使用在不同的上下文中,其能力與其他同類語言相比有過之而無不及。

Node.js事實上就是另外一種上下文,它允許在後端(脫離瀏覽器環境)運行JavaScript程式。

要實現在後台運行JavaScript程式,程式需要先被解釋然後正確的執行。Node.js的原理正是如此,它使用了GoogleV8虛擬機,來解釋和執行JavaScript程式。

除此之外,伴隨著Node.js的還有許多有用的模組,它們可以簡化很多重復的勞作,比如向終端輸出字串。

因此,Node.js事實上既是一個運行時環境,同時又是一個函式庫。

優點

但是,後端語言已經這麼多了,為什麼還要大費周章的將JavaScript移植到Server端呢?

這是因為JavaScript是一個事件驅動的語言,透過事件迴圈,能讓執行緒幾乎不會被卡住;而這樣的特性,非常適合用來接收高併發(High Concurrency)的請求。

例如在傳統的伺服器中,每個使用者的連接都會產生一個新的執行緒(看實作,不一定),並佔據一定的效能,伺服器在高併發的情況下,很容易就會由於應接不暇而無法服務新的流量;但Node.js會將每個request變成事件迴圈中待處理的事件,主執行緒只負責承接、轉拋、回應,並持續的在事件迴圈中循環,一切都以事件為核心在驅動程式運行,自然也就不會出現執行緒卡死的現象。

當然,如果是商業邏輯複雜的後端程式,效能瓶頸不在流量的服務,Node.js就無用武之地;但在設計需要承接高流量,且處理邏輯不太複雜時,Node.js可能就會是個可以考慮的選項。

功能

前面提到,Node.js就是一個可以執行JavaScript的環境,而這個環境除了提供瀏覽器Web API實作的setTimeoutsetIntervalconsole之外,也因為執行環境不同,有另外一系列的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分成了四種:timersI/O eventsimmediatesclose handlers,並依照順序輪流執行,其他在概念上還是一樣的:每個階段有自己的Queue,輪到它時清空Queue,到下個階段,周而復始。

為避免主執行緒阻塞,poll階段可以設定執行上限,到達上限時就會將Queue內的東西移交到pending callbacks階段的Queue中,下一個事件迴圈時再接續執行。

比較需要注意的地方是,微任務佇列(microtask queue)在每個階段結束後都會執行、清空,順序是先清空process.nextTickcallback,再執行其他的如Promisecallback

常有人誤解process.nextTick,會想問例如「一個Tick是多久?」之類的問題,但其實Tick指的就是事件迴圈中的一個階段,因此時間是不固定的喔!

結語

Node.js在上述中絕對是不只這些的,這邊只有整理一些基本的概念,還有很多東西沒有特別提到,提太多你也不想學了(我就是…哈);如果看不懂或是不了解,別著急。先看過知道有這東西,後面慢慢學習一步一腳印慢慢理解,最後必然突然開竅。


註:以上參考了
Node.js 是什麼?跟 JavaScript 有什麼關係
Node入門
狼叔:如何正确的学习Node.js