隨著 Node.js 的問世,前端開發者的觸角也逐漸蔓延到後端,甚至透過 Electron.js 這類強大的套件,也可以製作出完整的桌面 GUI 應用程式;藉由 Node.js,前端開發者得以使用較為熟悉的 JavaScript 為敲門磚,逐步的拓展自己的技術守備範圍。但為什麼為了網頁而生的語言可以透過 Node.js 跑在伺服器端呢?要解開這個問題,就得從認識 Node.js 出發。
本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您 前往購買 支持!
Node.js 是什麼呢?根據官網的說法:
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 移植到 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 擁有單執行緒的特性,且為了讓執行緒不會被需要等待的同步程式卡住,必須透過事件迴圈的機制來實現這個目標。如果各位讀者還有印象,我們在 這篇 有聊過瀏覽器中 JavaScript 的事件迴圈,其中有很大一部分是由瀏覽器完成的;在 Node.js 中則透過 libuv 來實現這部分的機制。不同於瀏覽器的事件迴圈,Node.js 中的事件迴圈大致會有以下幾個階段:
setTimeout
setInterval
給的 callbacksetImmediate
給的 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 這個 Server 端的 JavaScript 執行環境,並提到 Node.js 的語言特性在高併發情況的優勢,最後重點理解 JavaScript 的重要特色:事件迴圈,背後是如何在伺服器端執行的。
今天的 Node.js 介紹就先到這邊吧,明天我們繼續~
筆者
Gary
半路出家網站工程師;半生熟的前端加上一點點的後端。
喜歡音樂,喜歡學習、分享,也喜歡當個遊戲宅。相信一切安排都是最好的路。