選單

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

【CSDN 編者按】提及前端,JavaScript 是一門避不開的程式語言。不過在瀏覽器領域,本文作者認為直接使用 JavaScript 未必是最佳選擇,同時在開發過程中,使用編譯為 WebAssembly 的語言以及編譯為 JavaScript 的語言都有一定的缺點,那麼,下一代瀏覽器語言會是什麼樣,不妨透過本文的討論初探一下。

原文連結:https://uptointerpretation。com/posts/the-next-browser-language/

作者 |

Nicholas Yang

譯者 | 彎月     責編 | 屠敏

出品 | CSDN(ID:CSDNnews)

假設你正在編寫前端程式碼,可選擇的程式語言有多少種?

我認為這些語言可大致

分為三大陣營:

直接使用 JavaScript、編譯為 WebAssembly 的語言

以及

編譯為 JavaScript 的語言。

直接使用 JavaScript 需要的工具最少,但代價是除錯難度非常大,而且也不方便閱讀。

儘管新手可以選擇 JavaScript,但除了對“極簡主義”的痴迷之外,我看不到太多好處。

編譯為 WebAssembly 的語言雖然在不斷髮展,但仍然處於起步階段。

通常,這類程式語言會產生很大的二進位制檔案,因為大多數語言都需要提供額外的執行時。互操作性仍然是一個白日夢。即便兩種語言都能編譯成 WebAssembly,也不意味著二者之間一定可以相互交談。而且這些語言仍然需要趕上數十年來為 DOM 編寫的各種 JavaScript 庫。WebAssembly 也沒有類似於 React 或 Svelte 的庫。不要誤會我的意思,WebAssembly 有自己的使用場合。如果你想在瀏覽器中執行包含大量計算的原生程式碼,WebAssembly 是完美的選擇。但我不推薦日常前端開發選用 WebAssembly。

還有編譯成 JavaScript 的語言。這類語言實在不成氣候,我們不能對這個問題閉口不談。

ClojureScript、Elm、ReScript、Dart 等語言都有很不錯的社群,但我不認為它們的市場份額一定會擴大。這很可惜,畢竟編譯成 JavaScript 的語言可能是在瀏覽器中獲得良好體驗的最有效方式。它們允許你訪問 JavaScript 所沒有的功能,比如靜態型別、強型別、不變性、宏等。此外,它們還允許你訪問 JavaScript 以及廣泛的 JavaScript 生態系統, 而且它們不需要打包大型執行時。

有人認為有了 WebAssembly,人們可能就不願意將其他語言編譯成 JavaScript,因為 Wasm 才是瀏覽器程式設計時的“正版”編譯目標。但我不同意這種觀點。我們需要更多可以編譯成 JavaScript 的語言。在文字中,我想介紹一下我心目中未來的語言是什麼樣子。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

TypeScript

說起編譯成 JavaScript 的語言,就不得不提到 TypeScript。TypeScript 是一種很棒的語言,顯著提高了開發人員的體驗,增加了型別安全,發展出了更好的工具,而且替換成本也非常低。考慮到整個 JavaScript 生態系統的現狀以及與型別檢查 JavaScript 本身的難度,我認為 TypeScript 團隊取得了非凡的成就。

然而,一些針對 TypeScript 的批評也很公正。總結起來主要有兩大症結:

效能和合理性。

需要注意的是,TypeScript 團隊並非不知道這兩種批評意見。然而,這是 TypeScript 團隊在開發之初做出的明確權衡。在我看來,當時團隊為了能夠實現 TypeScript 而選擇這些權衡是非常明智的。

話雖如此,效能可以說是 TypeScript 最常被提及的問題。TypeScript 本身也是用 TypeScript 實現的,這個實現非常複雜。目前這個型別系統實際上是一種迷你程式語言,這會導致型別檢查的速度非常緩慢。

第二個問題是合理性。這個問題不太有人經常提及,但專注於程式語言的開發人員卻經常抱怨。TypeScript 有很多“洞”,如 allowJs 配置選項、any 型別和交集型別,因此這個型別系統無法確保程式碼是型別安全的。可以說,TypeScript 編寫的程式碼依然可能在執行時出錯。除此之外,TypeScript 的型別推斷只能處理最簡單的情況。很多時候,你必須明確標註型別。

然而,這兩個問題都是深思熟慮後的權衡結果。讓編譯器自己編譯自己是測試 TypeScript 的最好辦法。開發人員必須從語言的角度瞭解 TypeScript。更具體地說,他們必須體驗編寫大型 JavaScript 程式碼庫的感受,然後逐步在程式碼庫內加入型別。TypeScript 選擇了不實現嚴格的合理性,這樣開發人員就可以在現有的 JavaScript 程式碼庫中逐步採用 TypeScript,這也意味著開發人員只需要使用一個 any 型別就可以擺脫新增型別時的挫敗感。

可以說,TypeScript 是第一個純粹為了改善開發者體驗(而非語義)的語言。它沒有新增任何執行時結構,對效能沒有任何影響。相反,它添加了一個型別系統,更重要的是,它教會了社群如何使用型別、構建高質量工具、建立正確的文化。這本身就是一個不可思議的壯舉。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

下一個瀏覽器語言

所有這一切都表明,TypeScript 在 10 年前做出了一些對語言產生巨大影響的權衡。而現在,隨著時間的流逝,我認為是時候出現一種新的語言,並做出一系列新的權衡了。具體來說,我想要一種具有合理性、型別推斷,並且能夠快速編譯的程式語言。

但是,這些選擇帶來的相應的權衡是什麼?

首先,為了合理性,這門語言不會嘗試對各種 JavaScript 模式進行型別檢查,相反它會成為一門單獨的語言,使用更簡單的型別系統編譯成 JavaScript。它會把現有的 JavaScript 程式碼視為與之互操作的外部程式碼,對 JavaScript 程式碼進行執行時型別檢查,而且它還會用不同的原生語言實現。

為什麼我想要這樣的一種語言?

首先,我喜歡編寫具有合理性且相對簡單的型別系統的語言。我想要一種既可以在瀏覽器中執行,也可以在現有Web生態系統中執行的語言。編譯為 WebAssembly 的語言常常忽略 Web 生態系統的其餘部分。他們想在瀏覽器中逐個畫素地描繪原生 UI。雖然我認為這是一個很好的目標,但不是我的目標。我想使用這種語言來構建普通的日常網站。我不想要一種純函式式語言,我想要一種具有傳統 C 風格語法的語言,我想要一種語言來體現我在“工具的工具”方面的想法。

為什麼我認為現在這個時間點很合適?答案很明顯,現在是開始學習一門語言的第二佳時間,第一佳時間是 10 年前。但我也認為 JavaScript 社群在過去十年中發生了很大變化。人們學習了 TypeScript,並習慣了接收編譯器的反饋,也習慣了對資料進行建模。人們開始使用 Rust、Swift 和 Kotlin 等語言。人們開始懂得優秀的工具的意義。這並不是說十年前人們會拒絕型別安全的語言,只不過當時很難廣泛採用。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

ReScript/ReasonML

有些人可能覺得我描述的這種語言聽起來非常像 ReScript/ReasonML。

沒錯,二者在某些方面確實有重疊。但是,我的語言在理想情況下應該對 JavaScript 程式碼和特徵進行執行時型別檢查。執行時型別檢查有助於實現良好的互操作。使用其他 JavaScript 庫會相對容易一些。而且,我相信 traits 更適合使用者,它們可以對映成其他語言的特性,如 Java 介面和 C++ 概念。利用 traits 可以輕易實現一些特性,比如透過 Display trait 實現輸出任何型別。這個功能雖然看起來很淺顯,但可以避免一些本不應該出現的易用性方面的奇怪問題,例如“如何輸出這個?”或者“為什麼整數加法需要使用+,而浮點小數的加法需要使用+。”等。此外,我希望刪除一些額外的東西,如物件、連結串列、多型變體等。根據上一次的嘗試,我也不喜歡 ReScript 的開發人員體驗和錯誤訊息。

也就是說,我不排除 ReScript 有可能成為正確選項的可能性。由於我的經驗來自多年前,所以我認為可以再給這門語言一次機會。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

型別安全

我希望我的語言能用一種更系統的方法來實現型別安全。具體來說,我想採用 Rust 中實現不安全塊的方式來實現與 JavaScript 之間的互操作。也就是說,如果想呼叫 JavaScript,需要將程式碼包裝在一個不安全的塊中。這可以作為一個明確的標誌,表明你需要更仔細地閱讀這段程式碼。接下來只需為這些不安全的 JavaScript 庫呼叫編寫繫結即可。剛開始的時候,這個過程可以是手動的,但希望將來出現類似於 bindgen 和 cxx 之類的功能。

在 JavaScript 中,使用不安全塊的概念似乎是一個奇怪的選擇。JavaScript 的不安全和C的不安全並不一樣。但很多人沒有意識到的是,安全性指的並不僅僅是網路安全。

安全指的是能夠放心使用一個值、無需擔心它可能為 null 的能力。安全指的是能夠利用型別對領域進行建模,並且能確信建模是正確的能力。安全指的是可以隨意改變其內容,而無需擔心引入錯誤或混亂的能力。JavaScript 由於其動態的特性,本質上就是不安全的。而 Rust 的不安全塊可以讓使用者在擁有安全區的前提下,訪問大規模的不安全程式碼。基於瀏覽器的語言也應當如此。

至於執行時檢查,我相信為這個功能付出的額外開銷是值得的。我們已經有許多在 JavaScript 中進行模式驗證的先例了,只不過還沒有通用的規則。現在的模式驗證一般是自動推斷出一種能夠在執行時出錯的語言型別,或者對 JavaScript 值進行模式匹配。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

WebAssembly

我對 WebAssembly 未來的發展依然持樂觀態度。雖然新功能從建議到實現需要很長時間,但這可能是為了保證其質量。但我認為 WebAssembly 不一定會成為瀏覽器的通用執行時。可能這一點會有改變,但我認為 WebAssembly 更像是一種硬體加速器。當用戶需要使用適合硬體特性的強大計算時(比如固定寬度整數、靜態函式呼叫等),就會使用 WebAssembly ,就像是想用平行計算的使用者會使用GPU一樣。我認為,這種模型有實現異構計算的潛力,比如部分程式碼編譯成 JavaScript、部分程式碼編譯成 WebAssembly。這一點可以由使用者主動控制,也可以自動實現,甚至可以透過即時編譯實現。也許,透過對 JavaScript和Wasm 程式碼的控制,編譯器可以最小化兩者之間的互動,從而提高效能。甚至可以做成類似於將程式碼發給 WebGPU 之類的機制。

有可能有了這種模型,編寫需要大量計算的程式(如機器學習模型、影片遊戲、渲染軟體)就更容易了。

這種將程式碼編譯成 WebAssembly 和 JavaScript 的概念也可以體現在語言中。我希望能明確指定整型和浮點型,最好 Rust 的 usize 之類的索引型別。這樣,如果程式碼被編譯成 WebAssembly,就能享受 WebAssembly 的固定寬度整數帶來的好處。另一種可能性是,可以建立語言的一個子集,該子集可以編譯成 Wasm,並限制一些動態特性,如閉包、垃圾回收等。要訪問該子集,需要使用另一種 unsafe 風格的塊(或許可以是 strict 塊),或者也可以讓子集透過 dynamic塊訪問外部程式碼。這些都是假設,但我認為值得一試。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

實現

該語言很可能用 Rust 實現。主要是因為我很喜歡 Rust,我相信 Rust 帶來的算術資料型別、相對較快的程式碼、有限但夠用的可修改性和豐富的庫非常適合編寫編譯器。

如果 WebAssembly 進化得足夠好,其效能接近原生程式碼,我就會考慮用該語言的一個子集來編譯這個編譯器本身,將其編譯為快速的 WebAssembly。但至少 Rust 編寫的編譯器應該夠用幾年了。

JavaScript 未必是最優選,下一代瀏覽器語言會是什麼樣?

結論

你也許注意到了,型別安全和 WebAssembly 這兩節實際上是在討論系統語言的思想,如不安全塊、硬體加速等,想辦法將它們應用到基於瀏覽器的語言上。這種語言的設計就是這樣的。一些很有趣的程式語言都是在系統層次上實現的。我希望能在瀏覽器中實現它們。

雖然本文標題是《下一代瀏覽器語言》,但我想澄清一點,這並不是單一的一門語言。我希望出現多種語言,嘗試多種思路。希望本文能拋磚引玉,激發讀者在瀏覽器語言領域創新的興趣。

開啟App看更多精彩內容