前言javascript
Ryan Dahl之父發佈了新的項目Deno,不少IT媒體都使用了標題「下一代Nodejs」,首先咱們看一下Deno的特性:前端
1.支持typescript (nodejs目前也支持)。java
2.無package.json,無npm,不兼容nodejs。node
3.經過URL的方式引入依賴而非引入本地模塊,並在第一次運行的時候進行加載和緩存。git
4.能夠控制文本系統和網絡訪問權限以運行沙盒代碼,默認訪問只讀文件系統可訪問,無網絡權限。程序員
5.發生未捕捉錯誤時自動終止運行(這一點與nodejs同樣)。github
6.支持top-level的await。web
7.最終建立單一可執行文件(go語言特性)。typescript
8.能夠做爲庫引入,用於創建本身的Javascript Runtime。npm
8項特性中,有好幾個都是針對Node的痛點,包括無package.json,依賴包的引入,針對的就是被普遍吐槽的過大node_module。
附贈Deno Github地址:https://github.com/ry/deno
Deno詳解
先上一張圖來看一下javascript的發展簡史。
目前Deno只是一個demo,我花了一段時間,讀了一下deno的源碼,整個源碼並無提到nodejs。
在 high-level 層面,Deno 提供了一個儘量簡單的 V8 到系統 API 的綁定。爲何使用 Golang 替代 C++ 呢,由於相比 Node 而言,Golang 讓咱們更加容易的添加新特性。
咱們再對比一下二者的啓動性能。分別運行:
console.log('Hello world')
依然是相差懸殊,畢竟 deno 須要加載一個 TypeScript 編譯器。畢竟是一個 demo 版本,但願之後用力優化。
對於性能提高還有一個思路就是,可使用 LLVM 做爲後端編譯器把 TypeScript 代碼編譯爲 WebAssembly 而後在 V8 裏面運行,甚至能夠直接把源碼編譯成二進制代碼運行。Ryan Dahl 表示 deno 只須要一個編譯器,那就是 TS。可是既然 deno 要兼容瀏覽器,那麼 WebAssembly 應該也會被支持。
Deno 能夠對 ts 的編譯結果進行緩存(~/.deno/cache
),因此目前關注的就是啓動速度和初次編譯速度。
要麼就是在發佈前先行編譯,如此一來 deno 就脫離了開發的初衷了。deno 是一個 ts 的運行時,那麼就應該能夠直接運行 ts 代碼,若是提早把 ts 編譯成 js,那麼 deno 就回退到 js 運行時了。
初學者應該學習Node仍是Deno
對於這個問題,Ryan Dahl 的回答乾淨利落:
Use Node. Deno is a prototype / experiment.使用 Node。Deno 只是一個原型或實驗性產品。
從介紹能夠看到,Deno 的目標是不兼容 Node,而是兼容瀏覽器。
因此,Deno 不是要取代 Node.js,也不是下一代 Node.js,也不是要放棄 npm 重建 Node 生態。deno 的目前是要擁抱瀏覽器生態。
不得不說這個目標真偉大。Ryan Dahl 開發了 Node.js,社區構建出了整個 npm 生態。而且「Node.js 是前端工程化的重要支柱之一」。
雖而後來 Ryan Dahl 離開 Node.js 去了 Golang 社區,可是如今 Ryan Dahl 又回來了,爲 JavaScript 社區帶來了 Golang,開發出了 Deno,而後擁抱瀏覽器生態。
咱們看看 deno 的關於 Web API 的目標:
High level
Middle level
甚至還會包括 webGL 和 GPU 等的支持。
Deno的架構
Parsa Ghadimi 繪製了一張關於 Deno 的架構圖:
底層使用了做者開發的 v8worker2,而 event-loop 則基於 pub/sub 模型。
我比較好奇的是 deno 使用了 protobuf,而沒有使用 Mojo。既然目標是要兼容瀏覽器,卻不使用 Mojo,而是要在 protobuf 上從新造輪子,可見 Ryan Dahl 是真正的「輪子哥」啊。可是從 issue 中能夠看出,Ryan Dahl 以前是沒有據說過 Mojo 的,可是他看完 mojo 以後,依然以爲 protobuf 的選擇是正確的。
Mojo 是 Google 開發的新一代 IPC 機制,用以替換舊的 Chrome IPC。目前 Chrome 的最新版本是 67,而 Google 的計劃是在 2019 年的 75 版本用 mojo 替換掉全部的舊的 IPC。
Mojo 的思路確實和 protobuf 畢竟像,畢竟都是 Google 家的。舊的 IPC 系統是基於在 2 個進程(線程)之間的命名管道(IPC::Channel)實現的。這個管道是一個隊列,進程間的 IPC 消息按照先進先出的順序依次傳遞,因此不一樣的 IPC 消息之間有前後次序的依賴。相比之下,Mojo 則爲每個接口建立了一個獨立的消息管道,確保不一樣接口的 IPC 是獨立的。並且爲接口的建立獨立的消息管道的代價也並不昂貴,只需分配少許的堆內存。
Mojo 的架構設計:
咱們能夠看一下 Chrome 引入 Mojo 以後的架構變化。
以前:
以後:
是否是有點微服務的感受。
熟悉 Java 的 Spring 的能夠明顯看出這個依賴倒置。Blink 原本是瀏覽器最底層的排版引擎,經過 Mojo,Blink 變成了要給中間模塊。最近大熱的 Flutter 也是基於 Mojo 架構的。
TypeScript & Javascript
deno 的介紹是一個安全的 TypeScript 運行環境。可是咱們看源碼就會發現,deno 集成進了一個 TypeScript 編譯器,而入口文件中 ry/deno:main.go
// It's up to library users to call // deno.Eval("deno_main.js", "denoMain()") func Eval(filename string, code string) { err := worker.Load(filename, code) exitOnError(err) } // It's up to library users to call // deno.Eval("deno_main.js", "denoMain()") func Eval(filename string, code string) { err := worker.Load(filename, code) exitOnError(err) }
使用 V8 運行的 deno_main.js 文件。是 JavaScript 而不是 TypeScript 。
在前面的分析中咱們知道這會影響 deno 的初次啓動速度。那麼對於執行速度呢?從理論上,TypeScript 做爲一種靜態類型語言,編譯完成的 JavaScript 代碼會有更快的執行速度。我以前在《前端程序員應該懂點V8 知識》曾經提到過 V8 對於 JavaScript 性能提高有一項是 Type feedback。
當 V8 執行一個函數時,會基於函數傳入的實參(注意是實參,而不是形參,由於 JavaScript 的形參是沒有類型的)進行即時編譯(JIT):
可是當後面再次以不一樣的類型調用函數時,V8 會進行去優化(Deopt)操做。
(將以前優化完的結果去掉,稱爲「去優化」)
可是若是咱們使用 TypeScript ,全部的參數都是由類型標註的,所以能夠防止 V8 引擎內部執行去優化操做。
對deno性能的展望
雖然 TypeScript 能夠避免 V8 引擎的去優化操做,可是 V8 執行的是 ts 編譯後的結果,咱們經過字節碼或者機器碼能夠看到,V8 依然生成了 Type Check 的代碼,每次調用函數以前,V8 都會對實參的類型進行檢查。也就是說,雖然 TypeScript 保證了函數的參數類型,可是編譯成 JavaScript 以後,V8 並不能肯定函數的參數類型,只能經過每次調用前的檢查來保證參數的類型。
其次,當 V8 遇到函數定義時,並不知道參數的類型,而只有函數被調用後,V8 才能判斷函數的類型,纔對函數進行 Typed 即時編譯。這裏又有一個矛盾了,typescript 在函數定義時就已經知道了形參的類型,而 V8 只有在函數調用時才根據實參的類型進行優化。
因此,目前 deno 的架構還存在不少問題,畢竟只是一個 demo。將來還有不少方向能夠優化。
V8 是一個 JavaScript 運行時,而 deno 若是定義爲「安全的 TypeScript 運行時」,至少在目前的架構上,性能是有很大損失的。可是目前還不存在一個 TypeScript 運行時,退而求其次只能在 V8 前面放一個 TypeScript 編譯器了。
執行流程是這樣的:
雖然我在項目中沒有使用過 TypeScript ,可是基本上我在項目裏面寫的第三方庫都會提供一d.ts 文件。目前 TypeScript 最大的用途仍是體如今開發和維護過程當中。
咱們想到的一個方式就是 fork 一份 V8 的源碼,而後把編譯流程整合進去。TypeScript 在編譯爲 JavaScript 的過程當中也須要一份 AST,而後生成 js 代碼。V8 執行 js 代碼是再 parse 一份 AST,基於 AST 生成中間代碼(ByteCode)。若是 TypeScript 能夠直接生成對用的字節碼則會提高運行時的性能。
不過 Ryan Dahl 大概不會這麼幹。可是也未必,畢竟社區已經把 TypeScript 的一個子集編譯爲 WebAssembly 了。
以前微軟的 JScript 和 VBScript 在和 JavaScript 的競爭中敗下陣來,而如今 TypeScript 勢頭正猛。雖然對 ES 規範的兼容束縛了 TypeScript 的發展,但很期待微軟能夠提供一個 TS 運行時,或者在 Chakra 引擎增長對 TS 運行時的支持。