【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

三環沒有少發表於2019-03-04

在稍早前的 JS Conf Berlin 上,被稱為 Nodejs 之父的 Ryan Dahl 發表了《10 Things I Regret About Node.js》演講,並且釋出了新專案 Deno,值得一提的是,這是 Ry 的第二次公開演講,而第一次是釋出 Node.js,本文將帶領大家回顧一下 Ry 演講上所提到的重點。

【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

來自 twritter 網友 @malweene 的手繪概括

演講第一部分: Nodejs 的成功

這一部分,講了 Node 的發展歷程,Ry 認為 Node 在 I/0,事件驅動的 http server 方面已經做得很好了,提到了 Node 對一些協議的支援,跨平臺,以及 npm 生態系統等促成 Node 成功的因素,以及感謝了一些為 Node 做出過貢獻的人。 Ry 始終認為 JavaScript 是最好的動態語言,而動態語言用來做科學計算是合適不過了(這可能和 Ry 離開 Node 後加入 Google 的 Brain 團隊,從事深度學習方面的研究的歷程有關)。

演講第二部分: 對 Nodejs 的吐槽

這一部分可以說是整個演講的高潮,前後吐槽了 Node 上 7(不是應該 10 個麼???) 個讓 RY 覺得遺憾的設計。

1. 沒有堅持使用 Promise

Promise 是 async/await 的必要抽象,Promise 的沒有堅持使用導致後面 Node 的很多非同步 API 嚴重老化。

2. 沒有足夠的安全性

V8 本身是一個非常好的沙箱環境,但是 Node 在早期的設計中卻沒有利用好這一先天優勢,導致程式可以輕鬆訪問系統和網路。

3. 錯誤地堅持使用 GYP

由於 Chrome 放棄了 GYP,使得 Node 是 GYP 唯一的使用者,並且 Ry 認為這其中有太多的複雜且不必要的抽象,與其讓使用者自己去編寫 C++ 擴充套件來繫結 V8,不如提供一個核心外部函式介面來得更加可靠。Ry 認為在構建系統上的設計錯誤是 Node 的最大遺憾。

4. package.json

package.json 因為 require 的支援,使得這後來成了事實上的模組標準,可是很遺憾,因為默許了 package.json 的存在,可是 require(‘module') 又是不明確的,導致當出現本地依賴庫或者私有依賴庫時候,變得很混亂。並且 package.json 包含了太多冗餘描述,許可證,倉庫,描述等等,而且 package.json 提出的“module”作為檔案目錄也不是必要的抽象。

【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

5. node_module

增加了模組的解析複雜度,並且是偏離了瀏覽器語義,但是現在已經沒法剔除出去了。

6. require('module') 沒有加上副檔名".js”

多此一舉的做法,模組載入器必須得去猜測是‘.js’還是’.json’,並且也是跟瀏覽器語義不符的。

7. index.js

實際上預設去載入 index.js 也是沒有必要的,因為可能會有 index.html….

以上提到的遺憾都主要集中在程式碼管理上而非早期 Ry 關注的建立高效能伺服器上。實際上在 Ry 提出這些遺憾的時候,相當於已經提出了新一代 js/ts 的 v8 runtime 的原型 -> Deno,而其主要目標就是解決以上問題。

演講第三部分: 對 Deno 的介紹和期望

1.安全性

Deno 將利用 JS 是安全沙箱的事實,允許安全執行不受信任的程式

  • 預設情況下,不允許程式直接訪問網路或者檔案系統
  • 可以通過 —allow-net —allow-write 的方式訪問 不允許擴充套件函式直接繫結到 V8 上,簡化流程,也易於審計
  • 所有系統呼叫都通過訊息傳遞完成(protobuf 序列化)
  • 兩個原生函式: send 和 recv

【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

2.簡化模組系統

  • 不會去嘗試和現有 Node 模組系統相容
  • 僅匯入相對/絕對的 URL,並且匯入路徑必須提供副檔名
  • 遠端 URL 在第一次載入之後將被永遠快取,只有提供 --reload 才能再次獲取資源,可以通過指定非預設快取目錄來繞過

【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

3.將 TypeScript 編譯器內建於可執行檔案之中

  • Deno 內建 TS 編譯器以實現模組解析與構建結果的增量快取
  • 未修改的 TS 檔案不會被重新編譯
  • 普通 JS 也同樣有效
  • 利用 V8 的 snapshot 來快速啟動,暫未在原型中設計 (參考《使用 v8 snapshot 將啟動速度提升 8 倍》)

4.單個可執行檔案

【JSConf EU 2018】Ryan Dahl: Node.js 的設計錯誤

5.充分利用 2018 技術優勢

使用 Parcel 把 Node 模組編譯打包,來實現執行時的自舉。

以原生程式碼的方式提供強大的基礎設施

  • 已有其他機制負責實現 HTTP,而此前的 Node 是無法實現的
  • 目前 Deno 的非 JS 部分以 go 語言編寫,但還沒全面完成原型設計,其實 Rust 和 C++ 在某些方面也不錯

6.其它

  • 發生未捕獲 Promise 錯誤時直接終止程式
  • 支援 top-level 的 await
  • 相容瀏覽器(當功能重疊時)

Ry 的演講大致就是以上這些內容,儘管 Deno 目前還是不可用的,也沒有發行二進位制版本,但是該專案推出短短數日便獲得了上萬個 Star。

後話:

目前大前端開發的工程化,SSR 等能力基本都由 Node 提供,加上一些利用 Node 優勢而搭建的後端服務,都有一定發展時間,因此對於 JS 開發者而言 Node 在未來很長一段時間內依然是值得繼續學習的一個專案。

當然如果 Deno 有部分設計你是認可的,那現在最好的方法就是開始投資學習,從學習 Go 語言開始,學完 Go 就去看 Deno 原始碼,邊看還可以邊提 PR,看完 Deno 原始碼後 API 也差不多出來了,你就可以用 TypeScript 寫 Demo 了,最後即使 Deno 沒人用進了博物館,你還學會了 Go 和 Typescript,還為大型開源專案貢獻過原始碼....

參考資料:

相關文章