在前面的篇章裡,我們已經談過各種讓瀏覽器更強大的技術:從拖曳、攝影機、語音,到像 App 一樣的互動體驗,再到 IndexedDB 的資料儲存、Web Workers 與 WebSocket 即時連線。
今天要講的是一個更大的野心——讓 Web 能執行幾乎任意語言寫的程式:WebAssembly(Wasm)。🚀
和 Web Workers 的差別:
Web Workers 讓瀏覽器「跑得更有效率」
WebAssembly 則讓它「跑得更快」
傳統的網頁程式語言是 JavaScript。它靈活、普遍、可動態修改,但也有幾個天生的限制:
WebAssembly(Wasm) 的誕生,就是為了解決這些問題。它讓你可以 把 C/C++、Rust、Go 等語言的程式「編譯成一種中介碼」,在瀏覽器中以接近原生的速度執行。
簡單來說,WebAssembly 同時是一種 中介碼格式(bytecode),也是瀏覽器內建的 執行環境(VM / runtime)。瀏覽器可以解析 .wasm
檔案,就像能執行 JavaScript 一樣,只是它讀取的是更低階、強型別、機器友好的二進位格式。
「能編譯成 Wasm 的語言都能在瀏覽器裡運行」:各語言透過自己的編譯器或工具鏈,把原始碼轉成 Wasm bytecode,而瀏覽器的 Wasm 執行器負責運行這段 bytecode。換句話說,開發者只是把原本的輸出目標從 x86 / ARM 改成 Wasm 而已。
簡單講:WebAssembly 是瀏覽器的低階虛擬機(Virtual Machine)。
它讓 Web 不只「跑 JavaScript」,也能「跑原生級程式」。
想像你有一個 C 函式:
int add(int a, int b) {
return a + b;
}
你可以透過 Emscripten 把它編譯成 .wasm
二進位檔:
emcc add.c -O3 -s WASM=1 -o add.wasm
然後在 JavaScript 裡載入:
const wasm = await WebAssembly.instantiateStreaming(fetch("add.wasm"));
const { add } = wasm.instance.exports;
console.log(add(10, 20)); // 30
這樣你就讓 C 程式在瀏覽器裡運行了!🎉
WebAssembly 不是取代 JavaScript,而是讓 JS 可以「呼叫」更底層、更快的模組。
每種語言通常都有自己的進入 Wasm 世界的方式:
語言 | 對應工具或路徑 | 說明 |
---|---|---|
C / C++ | Emscripten | 最早、最成熟的 Wasm 編譯器。 |
Rust | wasm-pack | 官方提供完整 Wasm toolchain。 |
Go | 內建 GOOS=js GOARCH=wasm go build |
Go 1.11 起原生支援 Wasm。 |
Python | Pyodide | 讓 CPython 跑在 Wasm 上。 |
Java / Kotlin | TeaVM、JWebAssembly | 將 JVM bytecode 轉成 Wasm。 |
C# / .NET | Blazor WebAssembly | 透過 .NET runtime for Wasm。 |
簡單說:WebAssembly 並不綁定語言,它只是「執行的目的地」。
任何能編譯成 Wasm 的語言,都能在瀏覽器裡運行。
特性 | JavaScript | WebAssembly |
---|---|---|
語言層級 | 高階、動態型別 | 低階、強型別、接近組合語言 |
執行速度 | 由 JS 引擎 JIT 編譯,偏慢 | 編譯後接近原生速度 |
開發語言 | 只能用 JS / TS | 可由 C、C++、Rust、Go 編譯 |
操作 DOM | ✅ 直接可行 | ❌ 需透過 JS 間接呼叫 |
適合場景 | UI、邏輯、互動 | 重運算、影像、AI、遊戲核心 |
小結:JS 負責「控制」、Wasm 負責「效能」。
領域 | 範例 |
---|---|
遊戲引擎 | Unity、Unreal Engine 可直接匯出 Wasm 版本。 |
影像 / 音訊處理 | Adobe Photoshop Web 版使用 Wasm 來運算濾鏡。 |
AI 模型推論 | TensorFlow.js 可結合 Wasm backend,加速執行速度。 |
開發工具 | VSCode Web、Figma 都利用 Wasm 執行底層模組。 |
科學模擬 / 數據分析 | 原本需在本地跑的 heavy computation 移到瀏覽器。 |
假設我們要計算 1 到 n 的平方和。
JS 版本:
function sumSquaresJS(n) {
let sum = 0;
for (let i = 1; i <= n; i++) sum += i * i;
return sum;
}
Wasm 版本(C):
int sumSquares(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) sum += i * i;
return sum;
}
在 1 億次運算的情況下,Wasm 的效能往往可以快數十倍以上。
想直接體驗 WebAssembly 相較於 JavaScript 在大量運算下的性能優勢嗎?這個範例將計算從 1 到 N 的平方和,並比較兩者的執行速度。🚀
您可以從右方的控制台選擇不同的計算次數 (N),然後點擊「Start Test」按鈕來觀察兩者執行時間的顯著差異!
一個 .wasm
檔其實就是一個小型虛擬機模組,裡面包含:
JavaScript 可以和 Wasm 模組交換資料,但資料必須經過序列化(通常透過 ArrayBuffer
)。
瀏覽器 | 支援狀況 |
---|---|
Chrome | ✅ 完整支援 |
Edge | ✅ 完整支援 |
Firefox | ✅ 完整支援 |
Safari | ✅ 自 11 版起支援 |
目前各大框架(React、Next.js、SvelteKit)也能直接載入 .wasm
模組,透過 WebAssembly.instantiate
或 Webpack/Vite 的 plugin 方式整合。
在實務上,若你的 Wasm 模組需要長時間運算,還能搭配 Web Worker 背景執行:
const worker = new Worker('wasmWorker.js');
worker.postMessage({ n: 1e8 });
在 wasmWorker.js
:
self.onmessage = async (e) => {
const wasm = await WebAssembly.instantiateStreaming(fetch('sum.wasm'));
const { sumSquares } = wasm.instance.exports;
postMessage(sumSquares(e.data.n));
};
這樣主執行緒不會被卡住,體驗更接近原生應用。
WebAssembly 不是要取代 JavaScript,而是讓 Web 平台能「平衡開發便利與效能極限」。
它的存在,讓瀏覽器不再只是顯示頁面的工具,而是真正的應用執行平台。
JavaScript:靈活與互動。
WebAssembly:效能與計算。
當這兩者並肩而行,Web 才真正邁向「無邊界運算」的時代。
下一篇(Day 30),我們就要迎接最後的總結篇——回顧這 30 天,從 Canvas 到各式各樣的 Web API,瀏覽器到底變成了什麼樣的世界。🌍
👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯