問答方式學 Node.js

三毛丶發表於2018-12-27

Q: 什麼是 Node.js ?

A:Node.js 是指運於 web 服務端的 JavaScript,基於 Chrome V8 引擎,有非阻塞,事件驅動 I/O 等特性。

Q: 等等,你剛提到了 Chrome V8 引擎,它是什麼,為什麼使用它而不是其它引擎?

A:JavaScript 引擎是執行 JavaScript 程式碼的程式或直譯器,JavaScript 引擎可以實現為標準直譯器,或者以某種形式將 JavaScript 編譯為位元組碼的即時編譯器。它的工作流程大致如下:

問答方式學 Node.js

Chrome V8 引擎便是其中一種,由 Google 開發,使用 C++ 編寫,它的工作流程幾乎與上圖一致:

問答方式學 Node.js

相比於其它 JavaScript 引擎轉換成位元組碼或者解釋執行,V8 將 JavaScript 程式碼轉換成更高效的機器碼(IA-32, x86-64, ARM, or MIPS CPUs)。它通過 JIT(Just-In-Time)編譯器實現,不生成位元組碼或任何中間程式碼。並且使用瞭如 Inlining、Shapes、Inline Caches 等方法來提高效能。

Q:很好,現在我已經瞭解一點 Chrome V8 引擎有什麼用了,但是你列舉的那些方法,真讓我頭大。

A:比如 Shapes 與 Inline Caches 用來優化物件屬性載入。

Q:嗯?

A:ECMAScript 規範基本上將所有物件定義為由字串鍵值對映到 property 屬性的字典,其中 [[]] 雙方括號是規範定義不能直接暴露給 JavaScript 的屬性的表示方法。

問答方式學 Node.js

Q:在記憶體中也是這麼儲存?

A:不不不,如果在記憶體中這麼儲存,那就浪費空間了。比如說有相同形狀的物件 object = { x: 7, y: 8 },它們的屬性名是相同的,並且在屬性值的完整字典中,也只有 [[value]] 不同。

Q:那應該分開儲存,把除 [[value]] 之外的所有屬性名和其餘特性單獨儲存。並且它需要有一個屬性,來告知 JavaScript 引擎去哪查詢具體的值。

A:是的,引擎將物件的 Shape 分開儲存,如下 JSObject 只是儲存 [[value]]Shape 中有一個 Offset 偏移量來告知 JavaScript 取哪找具體的值:

問答方式學 Node.js

當有多個具有相同形狀物件時,優勢變得清晰可見。因為只需要將它們的形狀與鍵值屬性資訊儲存一次!

問答方式學 Node.js

Q:原來是這樣,不過那和 Inline Caches 有什麼關係?

A:關係大了,Shapes 主要是用來實現 Inline Caches(ICs)的,Inline Caches 是 JavaScript 快速執行的關鍵因素之一。

Q:
問答方式學 Node.js

A:比如有一個從物件中獲取 x 屬性的函式,在 JSC(JavaScriptCore) 中執行時,會生成以下位元組碼:

問答方式學 Node.js

Inline Caches 在第一個指令 get_by_id 指令中,由兩個未初始化的插槽組成。

當呼叫函式 getX({ x: 'a' }) 時,像前面所說,物件 { x: 'a' } 有一個包含屬性 x 的 Shape,該 Shape 包含屬性 x 的偏移量和其它特性,當第一次執行該函式時,會把該屬性的 Shape 和 偏移量儲存在 Inline Caches 中:

問答方式學 Node.js

後續呼叫該函式時,Inline Caches 只需要對比 Shape,如果與以前相同,則只需要從偏移量載入該屬性值。這比每次查詢要快很多。

Q:很精彩!

A:V8 所做的,遠不止這些,在即將要釋出的 7.2 版本中,解析時間明顯降低,縮短載入時間,提高響應速度:

問答方式學 Node.js

Q:好了,我們們不說 V8 了,我對你前面提到的非阻塞和事件驅動 I/O 挺感興趣的。

A:......

未完待續

參考

相關文章