我與Node.js重新認識的第2周 - Node.js 底層

macctown發表於2017-12-04
書接上次:《我與Node.js重新認識的第一週 - Node.js 風格特點》。這次讀了一些關於底層實現的東西:
  1. 《深淺》第3章 非同步I/O - node.js是如何實現非同步i/o的
  2. Udemy 《Learn and Understand NodeJS Learn and Understand NodeJS》 Section 2&3


V8引擎

首先,學習node.js一定要了解V8引擎,他是一個可以把js直接編譯成(處理器可以識別的)機器碼的東西。

再詳細點,V8是一個
  1. 開源的
  2. 用C++寫的
  3. 根據ECMA標準實現JavaScript
  4. 可以把JavaScript編譯成處理器可以識別的機器碼
  5. 可以獨立執行
  6. 也可以嵌入其他C++應用
的JavaScript引擎。

Node.js與V8引擎

普通青年使用V8:執行V8, JavaScript -> V8 —compile—> Machine Code
文藝青年則有這樣一個大膽的想法:
那些普通的js方法太沒意思了,能力優先。如果我可以寫一些C++程式碼,當做Add-on加到V8上,這樣V8就有能力識別具有更多的Javascript命令了,就更強大了。比如說file相關的東西,本來js不能做,現在我用c++在底部實現好,然後告訴V8,當使用者在js中寫道file.open(xxx)的時候,就來用c++執行file open的功能,這樣你的js(二b)就是有處理檔案能力的js(牛b)了。

文藝青年的想法其實就是我們的Node.js:一個把V8引擎嵌進去的C++應用,這個C++應用實現了超級多的customized新功能,這些功能使得這個應用(Node.js)非常的適合伺服器開發。

伺服器開發都需要什麼新功能呢 === Node.js實現的新功能都包括哪些方面呢:
  1. 管理可複用程式碼
  2. 處理檔案
  3. 處理資料庫
  4. 網際網路通訊
  5. 接受request,傳送respond
  6. 處理需要一定時間才能完成的工作


Node.js架構

  1. 第一層是C++ core,就是那些新加的customized功能 (其他講解中,還會提到比如event loop,libuv等,這些之後說)。
  2. 第二層是JS core,這一層用js實現,基於/呼叫C++ core,讓使用者可以更好的使用那些C++功能,同時也實現了許多常用的功能。
在node.js原始碼中,C++ core是在src資料夾內。JS core是在lib資料夾內。由此可見二者的層級關係。

Node.js 非同步I/O

Node.js如何實現非同步 I/O, 從JS到OS到底發生了哪些步驟(這個是udemy+《深淺》的合體版總結)

我與Node.js重新認識的第2周 - Node.js 底層

  1. 你寫的js程式碼呼叫了node.js的JS core (比如 fs相關功能:github.com/nodejs/node…),並且你設定了一個回撥函式
  2. JS core部分呼叫了C++ core (fs.js 呼叫的其中一個.cc: github.com/nodejs/node…)
  3. C++ core呼叫libuv
  4. C++ core呼叫libuv的方法來封裝請求物件(非同步I/O過程中重要的中間產物,中間指的是從js到os之間),其中包含了非同步I/O中最重要的東西之一:回撥函式。
  5. libuv把封裝好的請求物件發到OS
  6. 發到OS中的執行緒池(thread pool)等待被執行
  7. 執行緒池中某一執行緒將發來的請求物件中包含的I/O操作進行執行,結果存在該請求物件的req->result屬性中。然後提交完成狀態,也就是類似通知說"我完成了!”,之後把執行緒歸還給執行緒池
  8. 處於完成狀態的請求物件,被觀察者(圖中的兩個小人兒,不同型別的事件有不同的觀察者)在事件迴圈(Event Loop:大while迴圈,每個迴圈叫一個tick)中提出來(通過libuv中方法來檢查是否有執行完的請求),然後放到佇列(Completed Events Queue)中
  9. 事件迴圈從觀察者的佇列中取出處於完成狀態請求物件
  10. 取出其中包含的I/O操作執行結果以及回撥函式,發到V8中執行。到這就達到了呼叫#1中設定的回撥函式的目的。
a. V8引擎執行的JavaScript是同步的(sync)(stackoverflow.com/questions/2…)且單執行緒
b. #1-#9 與 #10 是同時在工作的,I/O事件一個一個執行,然後最後傳送到V8引擎中一個一個(因為JS是同步的)的執行回撥函式
c. 由於b,整個Node.js有了非同步I/O的能力
d. 事件驅動(event driven)、非阻塞(non-blocking)I/O的特點也就可以解釋了。事件驅動就是指的#7-#10,事件被完成觸發了之後各個步驟,直到最後執行回撥函式。非阻塞I/O就是整個#1-#10這個過程,我們在V8中執行的JavaScript程式碼並不會因為事件的執行而停止,#1-#9和#10同時工作,一個執行I/O事件,一個得到通知執行回撥函式。
e. 從d的解釋中,可以更好的理解上一篇文章中最後那段說Node.js是單執行緒/多執行緒。

下次寫事件(Event)和事件發射器(Event Emitter)相關的東西。歡迎大家交流,指正~


相關文章