最流行的 WebAssembly 語言,會是 JavaScript 嗎?

對於網路平臺而言,WebAssembly 的出現無疑是意義重大的,它能讓各種語言編寫的程式碼以接近原生的速度在 Web 中運行——那麼在各種語言中,JavaScript 會是其中最流行的嗎?

原文連結:https://thenewstack.io/will-javascript-become-the-most-popular-webassembly-language/

未經允許,禁止轉載!

作者 | Mary Branscombe

譯者 | 彎月 責編 | 鄭麗媛

WebAssembly 是從瀏覽器中發展而來的,因此很多人認為 JavaScript 很適合 WebAssembly。然而,最初 WebAssembly 的目標是編譯其他語言,以便開發人員可以在瀏覽器中通過 JavaScript 與這些語言互動(生成在瀏覽器中運行的 Wasm 編譯器會創建 Wasm 模組,以及允許 Wasm 模組訪問瀏覽器 API 的 JavaScript 填充程序)。

如今,有幾款在伺服器端運行的 WebAssembly 非瀏覽器運行時(包括 Docker 的 Wasm 支持),在這類運行時中,Wasm 模組實際上是在 JavaScript 運行時(如 V8)中運行的,因此即使 WebAssembly 運行時日漸普及,與 JavaScript 保持一致仍然很重要。

Wasm 是支持多種語言的,永遠都是,例如最近 Wasm 的發展重點是支持 Rust、Python、Ruby 和 .NET 等許多語言。但 JavaScript 也是世界上最流行的程式語言之一,很多重要提升都是為了使用 JavaScript 作為編寫可編譯為 WebAssembly 模組的語言,還有很多人在嘗試將提高 JavaScript 性能的經驗應用到 Wasm。

開發者的需求

開發者的需求

Fermyon 在發佈用於為 Spin 框架構建元件的 SDK 時,首先使用了 .NET,然後使用了 JavaScript 和 TypeScript。執行長 Matt Butcher 進行客戶調研,希望找出他們喜歡使用的語言:「你對什麼語言感興趣?你用什麼語言編寫程序?你喜歡用什麼語言寫程序?基本上,JavaScript 和 TypeScript 都排在前三名。」(開發人員選擇的第三種語言是 Rust,可能是因為 Wasm 的 Rust 工具普遍比較成熟;另外 .NET、Python 和 Java 也很受歡迎。)

Butcher 表示,Suborbital 在推出用於構建伺服器端擴展的 JavaScript 支持時,也看到了類似反應,JavaScript 很快就成為了構建伺服器端擴展時最受歡迎的開發語言。

目前,在 Fermyon 的客戶中,31% 的人希望支持 JavaScript,20% 希望支持 TypeScript。雖然不清楚支持這兩種語言的開發人員是同一夥人,還是各代表一半的開發人員,但很明顯 JavaScript 大幅領先。對此,我們感到很驚訝——我們原以為 JavaScript 社區會反對 WebAssembly 支持 JavaScript,但結果完全相反。

Butcher 曾認為,編寫 WebAssembly 的語言之間會出現更激烈的競爭,但這些反應改變了他的想法:「這些語言之間不會形成競爭。WebAssembly 將變成每個了解 JavaScript 的開發人員都可以編寫和運行的一個場所。說到底,人們還是想要 JavaScript。」

Butcher 的觀點符合阿特伍德定律(任何可以用 JavaScript 來寫的應用,最終都將用 JavaScript 來寫),同時位元組碼聯盟技術指導委員會主任 Bailey Hayes 也提到了 Gary Bernhardt 著名的 JavaScript 的誕生和死亡(他預言了WebAssembly這類運行時的誕生,而且還將JavaScript比作可以在世界末日中倖存下來的蟑螂):

「Rust 很難學,雖然它很受歡迎,但學習曲線十分陡峭。如果是剛開始學的新手,我希望他們從已掌握的知識入手讓開發人員使用他們熟悉的工具探索 WebAssembly 這樣的新領域,可以提高他們的效率,並打造更好的軟體生態系統」,「很明顯,我們都看好 JavaScript,因為它是世界上最受歡迎的語言,我們希望讓儘可能多的人使用 WebAssembly!」

開發人員想用 JavaScript 做什麼

Butcher 將 WebAssembly 的使用分為四大類:瀏覽器應用程序、雲應用程序、物聯網應用程序和外掛應用程序——而 JavaScript 涉及以上所有領域。

「我們看到開發人員用 JavaScript 和 WebAssembly 為大量面向 JavaScript 的前端編寫後端,為前端的 React 應用提供資料,然後使用 JavaScript 後端來實現資料儲存或處理。」

Hayes 指出,伺服器端 Wasm 有明顯的優勢:「使用伺服器端 JavaScript 的人可直接上手編寫伺服器端 Wasm,從而通過更少的程式碼構建更快的程序,他們可以享受各種好處,且不會遇到任何阻力。」

Butcher 認為還有一些在 WebAssembly 中使用 JavaScript 的建議非常有創意,「關於為什麼希望 WebAssembly 支持 JavaScript,有人闡述了一個非常有趣的原因:你可以創建一個更安全的 JavaScript 沙盒,然後在 WebAssembly 內部執行任意不受信任的程式碼,並使用瀏覽器版本的 JavaScript 接口來防止不受信任的 JavaScript 干擾其他受信任的程式碼。」

能夠在 Wasm 沙盒中隔離不受信任的程式碼片段是嵌入式 WebAssembly 的常見用例,SingleStore、Scylla、Postgres、TiDB 和 CockroachDB 一直在嘗試使用 Wasm 儲存過程。

Fastly 的 js-compute 運行時是運行在 WebAssembly 上的 JavaScript,用於邊緣運算;Suborbital 專注於外掛;Shopify 最近添加了 JavaScript 作為利用 WebAssembly 函數自定義後端的首選語言;而前段時間發佈的 RedPanda 也支持 WebAssembly(也是使用 JavaScript)。

RedPanda 的 WebAssembly 模組公開了一個 JavaScript API,用於編寫如何在其與 Kafka 相兼容的流媒體平臺上儲存資料的策略,執行長 Alex Gallego 表示,這是因為 JavaScript 的靈活性以及在開發人員中間的流行度。

靈活性對於平臺開發人員來說很重要。Alex Gallego 指出:「在設計新產品時,最大的困難是設計長期的 API。一旦你做出承諾,人們就會將這些程式碼投入生產,然後你就永遠無法再刪除,如果做出錯誤的決定,就會陷入困境無法自拔。從框架開發人員的角度來看,你可以利用 JavaScript 超快地迭代,並根據社區的反饋相對更容易地修改接口,因為它是一種動態語言。」

開發人員可以藉助 JavaScript 獲得熟悉的業務邏輯程式設計模型,例如遮蔽證件號碼、查找特定年齡段的使用者或對 IP 地址進行信用評分,所有這些工作都不需要分散式儲存和流媒體管道複雜性方面的專家來做。「多執行緒、向量化指令、IO、設備處理、網路吞吐量的可擴展性維度,所有核心的棘手問題仍由底層平臺處理。」

JavaScript:流行度與高性能

JavaScript:流行度與高性能

流行度是吸引開發人員使用 JavaScript 編寫 WebAssembly 模組的常見原因。

在一項新服務推出時,開發人員必然沒有任何使用經驗,但是因為他們了解 JavaScript,所以更容易快速上手。Gallego 指出,這為平臺提供了一個龐大的潛在客戶社區。

「在使用 WebAssembly 時,你可以混合多種程式語言,但我認為選擇 JavaScript 才是正確的。這門語言非常容易,很友好,有很多包,還有數不盡的開發者教程。隨著公司的發展,你需要招攬更多人才,一般這都很有挑戰性,但僱傭 JavaScript 開發人員相對要容易得多。」

「在公開 API 時,你必須尋找合適的設計,對我來說,融入最大的程式設計社區是一個非常關鍵的決定。」

Fastly 的 Guy Bedford 表示,「JavaScript 是使用最廣泛的語言之一,由於其採用率,這門語言有著舉足輕重的作用。同樣,WebAssembly 擁有很多優勢,例如具有安全性、高性能以及可移植性等,因此可以部署到不同的環境。很多公司都在用 WebAssembly 做些非常有趣的事情,而他們希望支持來自這些現有生態系統的開發人員。」

JavaScript 有一些明顯的優勢,Bucher 指出:「門檻低,學習的資源種類繁多,你可以通過 npm 獲得數不盡的庫。」我們之所以考慮將 JavaScript 與 WebAssembly 結合到一起,庫是其中一個很重要的原因。

「如果你開發了一個非常擅長矩陣乘法的庫,那麼就應該竭盡所能利用好開發這個庫所花費的大量時間。」Gallego 建議,憑藉這些優勢,JavaScript 在 Wasm 中的地位就像 SQL 的地位一樣。

JavaScript 長達 20 年的最佳化也是一個很大的優勢。他指出,「人們為這個生態系統投入了大量資源,專家們會想方設法加快網站的渲染速度。V8 JavaScript 引擎背後的程式設計團隊甚至加入了 Java 垃圾收集器創建者這樣的優秀人才。致力於提高 JavaScript 性能的程式設計師大概是這個世界上最專注於此的人,這股力量比其他任何東西都強大。」

「我認為,這就是 JavaScript 長盛不衰的原因,其背後站著一群聰明有才華的人,他們不僅注重規範級別,也很有行動力。」

他指出,「JavaScript 的單執行緒性能非常棒,非常適合邊緣運算,WebAssembly 與 JavaScript 的組合將成為一個真正可行的成熟應用程序開發工具。」

同樣,Butcher 考慮在 WebAssembly 雲上對 React 應用程序進行伺服器端渲染,以應對無法在瀏覽器中運行大量 JavaScript 的設備。

他表示,「V8 擁有非常出色的性能最佳化。即便是 Python 和 Ruby 這類的成熟語言也沒有像 JavaScript 一樣如此注重性能最佳化,一而再,再而三地提升速度。」

「性能非常重要,而且 JavaScript 運行時很容易採用……在我看來,大家確實很想要一個可以在 WebAssembly 中運行的版本。這樣就可以繼續長期以來一直享有的好處。」

但如今 WebAssembly 還沒有做好準備為主流 JavaScript 開發人員所使用。

Bedford 警告說,「JavaScript 的入門門檻很低,不需要擁有學位或大量經驗,它是一種非常容易理解的語言。但如果你是一名 JavaScript 開發人員而且想使用 WebAssembly,那麼真正掌握使用方法並不容易。」

將 JavaScript 引入 Wasm 的不同方式

你可以使用 JavaScript 來編寫 WebAssembly 模組,但 Cosmonic 執行長 Liam Randall 表示:「在未來幾個月,位元組碼聯盟將推出重大更新,提供更多的 JavaScript 支持。」

Randall 說道:「今年構建、創建和操作元件的能力方面取得了重大進展,其中最重要的兩種語言分別是 Rust 和 JavaScript。」

目前,最流行的方法是使用 QuickJs 直譯器(最初由 Shopify 採用並推廣,這個包非常小,只有 210KB),許多 WebAssembly 運行時中都包含這個包。例如,Shopify 的 Javy 和 Fermyon 的 spin-js-sdk 都使用了Quickjs 與 Wasmtime 運行時(早期與 TypeScript 綁定,但尚未將 JavaScript 作為官方支持的語言),而且還有一個面向 CNCF WasmEdge 運行時的 QuickJS 版本,既支持在 WebAssembly 中使用 JavaScript,而且也允許在 JavaScript 中調用 C/C++ 和 Rust 函數。

QuickJs 支持 ECMAScript 2020 的大部分功能,包括字串、陣列、對象以及支持它們的方法、非同步生成器、JSON 解析、正規表示式、ES 模組和可選的運算子過載、BigDecimal 和 BigFloat。所以,這個包可以運行大部分JavaScript程式碼。除了比較小之外,這個包還非常快,併為運行 JavaScript 提供了良好的性能——但它不支持 JIT。

使用 QuickJs 可以有效地捆綁在 JavaScript 運行時中,而且這種簡約有一個很大的好處,Hayes 指出:「通常包的規模越大,性能就無法做到完美,但大多數情況下依然可以正常使用,我看到很多地方都採用了這個包。」

Fermyon 的 JavaScript SDK 建立在基於QuickJs的Javvy 之上,同時還使用了 Wizer 預初始化來保存程式碼初始化後的快照,從而加快 QuickJs 的啟動時間。Butcher 解釋道,「Wizer 可以加快 .NET 在 WebAssembly 上的運行速度,它從運行時開始,載入 .NET 的所有運行時環境,然後將其作為新的 WebAssembly 模組寫回磁碟。我們發現使用QuickJs也可以採用相同的方法。」

「在允許spin構建時,SDK會獲取 JavaScript 運行時,獲取源檔案,使用 WIZER 對其進行最佳化,然後將所有這些打包併發送到一個新的 WebAssembly 二進位制檔案中。」

通過預最佳化解釋型語言的程式碼來提高速度的思路聽起來很熟悉,因為大多數瀏覽器的 JavaScript 引擎就採用了這種方法。「引擎在解釋JavaScript的同時將JavaScript檔案發送給最佳化器,只需幾毫秒,就可以從解釋模式切換到編譯最佳化模式。」

「不為人知的是,實際上WebAssembly集合了我們從 JavaScript、Java、.NET 積累的一切經驗。我們在過去的15~20年間使用這些語言積累的經驗的基礎之上,構建了WebAssembly。」

添加 JIT

添加 JIT

Shopify 還與 Igalia 簽約,將 Mozilla JavaScript 引擎 SpiderMonkey 引入 Wasm;而 Fastly 則採用了 compontentize-js 法,使用 SpiderMonkey 以在瀏覽器中以高速模式運行 WebAssembly 的 JavaScript 程式碼,由 JIT 負責編譯 JavaScript 程式碼並在 WebAssembly 直譯器中運行。

儘管 WebAssembly 模組具備充分的可移植性,可以在許多不同的地方使用,但將多個 Wasm 模組組合成一個程序非常不容易。Wasm 中的類型支持很原始,各種模組可能需要的不同 WebAssembly 功能,而這些功能被分組到不同的「世界」(如 Web、雲和 CLI),並且每個模組通常都會定義自己的本地地址空間。

Bedford 表示,「WebAssembly 的問題在於,獲得某個二進位制檔案後,實際上你得到的只是非常低級的綁定函數,接下來你需要付出大量努力才能將所有二進位制檔案連起來。你必須專門花精力連接每種語言,需要對輸入輸出的資料進行復雜的變換處理,所以你必須是一個非常有經驗的開發人員才能知道如何處理。」

WebAssembly 的元件模型添加了依賴項描述以及高級的、獨立於語言的接口,用於傳遞值和指針。這些接口解決了上述所說的「完全不共享記憶體空間的高級封裝問題」。

他解釋道,「你有的不只是一個盒子,而是一個帶有接口的盒子,盒子之間可以互相交談。你可以擁有函數和不同類型的結構以及對象結構,你還可以擁有跨越元件邊界的資料結構。」

Compontentize-js 就建立於此基礎之上,允許開發人員使用任意綁定。「我們可以根據你的綁定和想要運行的 JavaScript 模組,給你一個 WebAssembly 二進位制檔案,它代表整個 JavaScript 運行時和擁有這些綁定的引擎。我們可以非常快速地提供這個二進位制檔案,而且可以生成非常複雜的綁定。」

這個過程不需要很多額外的 WebAssembly 構建步驟,JavaScript 開發人員可以使用熟悉的工具,並通過 npm 安裝庫。

儘管從規模上看,SpiderMonkey 比 QuickJs 更大(Bedford 估計帶有 JavaScript 運行時的二進位制檔案和開發人員的 JavaScript 模組大約為5~6MB),但依然非常小,足以快速初始化,可用於邊緣運算硬體。

這種方式同樣使用 Wizer 來最佳化初始化性能,這樣就可以縮短冷啟動時間。「我們會在調用函數之前,預先初始化所有 JavaScript,所以JavaScript引擎不需要進行初始化處理。一切都已使用 Wizer 進行了預初始化。」

這不是提前(Ahead Of Time,AOT)編譯,但今年晚些時候或明年,omponentize-js 將使用 Bedford 建議的部分評估技術進行更高級的運行時最佳化,這樣就可以實現AOT。「因為你知道綁定了哪些函數,所以可以使用二村對映評估直譯器,並獲得這些函數的編譯版本,作為SpiderMonkey本身評估直譯器的一部分。」

Compontentize-js 是位元組碼聯盟的一個名叫jco項目的一部分,jco 是一個為 WebAssembly 打造的JavaScript 元件工具,目前還是處於實驗階段的 JavaScript 元件工具鏈,並非該 JavaScript 運行時特定的工具。Bedford 解釋說,「我們的基本思路是,構建一個更通用的工具,無論將 WebAssembly 放在何處,都可以使用 JavaScript 編寫一小段程式碼。」

Randall 指出,Jco 是一個「徹頭徹尾的 JavaScript 新體驗」項目,這表明我們可以期待在 wasmtime 的下一個版本中看到更成熟的 JavaScript 和 Rust 元件版本。重要的是要注意,這些仍處於實驗階段,WebAssembly 元件模型尚未發佈,Bedford 稱 componentize-js 為研究,而非預發佈軟體:「我們的目標是為處於該領域最前沿的開發人員提供這些功能,目前只是邁出了第一步。」

實驗性的 lightjs 針對的也是 WebAssembly 元件模型,他們創建的 Wasm 接口類型綁定可以共享 JavaScript 的類型和定義。到目前為止,wit-bindgen 生成器(為希望編譯為 WebAssembly 並與元件模式一起使用的程序開發人員提供語言綁定)僅支持編譯語言,C/C++、Rust、Java 和 TinyGo,因此添加JavaScript之類的解釋型語言可能具有一定的挑戰性。

雖然 spin-js-sdk 可以專門為 Spin HTTP 觸發器生成綁定,但 SlightJs 的目標是為開發人員提供Wasm 接口類型綁定。最終,它將成為微軟 SpiderLightning 項目的一部分,該項目將為開發人員提供使用 Wasm 接口類型構建雲原生應用程序時所需的功能,為運行使用 SpiderLightning 的 Wasm 應用程序的輕量級命令列工具添加 JavaScript 支持。

目前,SlightJS 使用的是 QuickJs,因為QuickJs的性能更好,但隨著 SpiderMonkey 的改進,將來可能會轉變,Butcher 指出了 JIT 風格的 JavaScript 運行時具備的性能優勢。QuickJs 本身在很大程度上取代了早期的可嵌入 JavaScript 引擎 Duktape。

Bedford 表示,「目前相關的活動呈爆炸式增長,該領域正在加速發展。」

JavaScript 與 Wasm 的共同提升

TC39 ECMAScript 工作組副主席 Daniel Ehrenberg 建議,你可以將以上這些方法想象成「JavaScript 腳本在上層,而WebAssembly 在下層」,但還有一種方法是「JavaScript 和 WebAssembly 並排放置,而底層是 JavaScript 虛擬機器。」

後一種方法是 Bloomberg 和 Igalia 長期以來的努力方向,這種建議旨在實現 JavaScript 與 WebAssembly 之間的高效互動,例如引用類型字串可以降低WebAssembly 程序使用 JavaScript 字串的難度,而 WebAssembly GC 的垃圾收集可以簡化記憶體管理。

TC39 聯合主席兼 Bloomberg 基礎設施與工具團隊負責人 Rob Palmer 解釋說,字串在兩種語言之間更好地協同工作可以提高效率。「目前二者還無法真正做到高效,因為在兩個域之間複製字串的開銷超過了 WebAssembly 提供的速度提升。」

WebAssembly GC 給 JavaScript 帶來的不僅是 JavaScript 的弱引用和 finalization registry,還提供了 WebAssembly 線性記憶體與基於 JavaScript 堆的記憶體之間的最小限度的互操作性,從而允許編譯一些 Wasm 程序。Ehrenberg 解釋道,「WebAssembly 不僅具有線性記憶體,而且還可以分配幾個不同的垃圾收集分配對象,這些對象指向彼此,具有完全自動的記憶體管理。你只需要追蹤引用,‘死掉’的東西都會自動消失。」

在 WASI 中支持執行緒,通過並行化提高性能,並提供對現有庫的訪問,這些工作尚處於早期階段 (最初僅適用於 C,目前尚不清楚如何與元件模型協同工作),但這兩個 WebAssembly 提案完成得非常好,希望很快就能在瀏覽器中推出,以幫助到一系列開發人員。

「這在一定程度上能夠方便我們將 Kotlin 之類的語言編譯成 WebAssembly,而且效率高於自己動手分配記憶體,此外還能方便我們在 JavaScript 和 WebAssembly 的並排架構中實現零複製的記憶體共享。」

對於伺服器端 JavaScript,Ehrenberg 表示很欣慰看到兩種方法之間互相協調的跡象,這兩種方法最初似乎朝著不同的方向發展:WinterCG API 旨在方便在伺服器端環境中使用 Web 功能,而 WASI 則旨在為 WebAssembly 提供更強大的 IO 功能。

他指出,「我們希望能夠在 Deno 中使用 WinterCG API,同時也希望能夠在 Shopify 的 JavaScript 環境和 Fastly 的 JavaScript 環境中使用 WinterCG API,後兩種環境是使用 WASI 在 WebAssembly 之上實現的。目前人們正在努力在 WebAssembly 之上實現 JavaScript,他們正在研究 JavaScript 能否支持 WinterCG API,然後這些 WinterCG API 能否在 WASI 中實現。」

多語言 Wasm 的發展前景

多語言 Wasm 的發展前景

JavaScript 的靈活性使其成為探索元件化以及可組合性的好方法,我們可以利用 JavaScript 為 WebAssembly 元件模型提供更多可能性,而這一切如今還處於萌芽狀態。

JavaScript 與 Rust 將成為構建模組化 WebAssembly 體驗的首選語言,Randall 預測將來這種體驗將普及到所有語言,開發人員可以混合不同語言編寫的多個 WebAssembly 元件,並將它們組合在一起創建新的應用程序。

「我可以使用高性能且安全的 Rust 來構建雲元件,就像 wasmCloud 那樣,將不太複雜的元件組合起來,用 JavaScript 編寫面向使用者的程式碼。我可以使用來自世界各地不同的 JavaScript 元件並將它們結合在一起,也可以使用 Rust 編寫的元件,還可以通過許多不同的方式重構這些元件。」

Bedford 表示贊同,「你可以讓 Rust 與 JavaScript 對話,在沙盒中運行程式碼,或者用一個高度最佳化的 Rust 元件做一些繁重的工作,然後用 JavaScript 編寫高層元件。」

compontentize-js 允許你使用 JavaScript,並將其捆綁為 WebAssembly 元件;而 Jco 工具鏈以及類似工具(如同樣依賴於元件模型的 cargo-component)則可以通過這種方式使用多語言。

Beford 解釋道,」必須由某個人熟悉 Rust 應用程序並編寫一些 JavaScript——編寫並維護 JavaScript 的綁定生成。而使用元件模型就不需要考慮JavaScript 了,他們只需關注元件模型,提供多種語言的支持,而 JavaScript 開發者只需使用元件即可。「

「這就是元件模型為這些工作流程帶來的便利性。有人可以用 Rust 編寫元件,而你可以很方便地在 JavaScript 環境中使用這些元件。然後在瀏覽器之外,JavaScript 開發人員也可以一展所長。」

他指出,Rust 開發人員也可以通過這種方式使用 JavaScript 元件,「Jco 是一個 JavaScript 元件工具鏈,它支持使用 JavaScript 創建和運行 JavaScript 元件。」

Hayes 建議,將來開發者可以通過 wasm-compose 庫將兩個元件結合起來。未來幾年內,元件模型將成為 WebAssembly 中一個非常有趣的探索方向:

「如果你熟悉 JavaScript 和 Rust,可以將兩大語言生態系統結合在一起,二者之間可以互操作,人們則可以選擇最好的庫或工具。我非常期待 WebAssembly 的元件,因為從理論上講,它可以打破前端與後端工程師以及語言生態系統之間的孤島。」

相關文章

Python 與 JavaScript 做比較公平嗎?

Python 與 JavaScript 做比較公平嗎?

在討論應該使用 Python 還是 JavaScript 構建項目時,一般我們都不會說只使用一種程式語言來構建所有的元件。 在現代軟體開發中...

WebAssembly 真能取代 Kubernetes?

WebAssembly 真能取代 Kubernetes?

摘要:許多開發者總是習慣性地將 WebAssembly 與 Kubernetes 進行對比,也許將來可能會出現某種技術,在雲環境中部署和管理...

TypeScript 這十年

TypeScript 這十年

【CSDN 編者按】很多時候,僅從名稱上來看,不少人對 TypeScript 與 JavaScript 傻傻分不清楚,或許只知道 TypeS...