iT邦幫忙

2025 iThome 鐵人賽

DAY 29
1
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 29

Day 29 - WebAssembly 是什麼?讓 C/C++、Rust、Go 在瀏覽器跑、超越 JavaScript 的效能

  • 分享至 

  • xImage
  •  

在前面的篇章裡,我們已經談過各種讓瀏覽器更強大的技術:從拖曳、攝影機、語音,到像 App 一樣的互動體驗,再到 IndexedDB 的資料儲存、Web Workers 與 WebSocket 即時連線。

今天要講的是一個更大的野心——讓 Web 能執行幾乎任意語言寫的程式WebAssembly(Wasm)。🚀

和 Web Workers 的差別:
Web Workers 讓瀏覽器「跑得更有效率」
WebAssembly 則讓它「跑得更快」


為什麼需要 WebAssembly?

傳統的網頁程式語言是 JavaScript。它靈活、普遍、可動態修改,但也有幾個天生的限制:

  • 執行效率比不上原生應用(C/C++、Rust)。
  • 大量計算(如影像處理、AI 推論)容易讓 UI 卡頓。
  • 無法直接重用其他語言既有的生態或函式庫。

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」,也能「跑原生級程式」。


一分鐘理解:WebAssembly 是怎麼運作的?

想像你有一個 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 的差異

特性 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 移到瀏覽器。

範例:Wasm 加速計算

假設我們要計算 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 的效能往往可以快數十倍以上。


範例 Demo

想直接體驗 WebAssembly 相較於 JavaScript 在大量運算下的性能優勢嗎?這個範例將計算從 1 到 N 的平方和,並比較兩者的執行速度。🚀

您可以從右方的控制台選擇不同的計算次數 (N),然後點擊「Start Test」按鈕來觀察兩者執行時間的顯著差異!


Wasm 模組的結構

一個 .wasm 檔其實就是一個小型虛擬機模組,裡面包含:

  • 匯入表(imports):從外部(如 JS)引入函式。
  • 匯出表(exports):提供給外部呼叫的函式。
  • 記憶體區塊(memory):線性記憶體,像是 ArrayBuffer。
  • 全域變數(globals)函式表(functions) 等。

JavaScript 可以和 Wasm 模組交換資料,但資料必須經過序列化(通常透過 ArrayBuffer)。


支援度與現況

瀏覽器 支援狀況
Chrome ✅ 完整支援
Edge ✅ 完整支援
Firefox ✅ 完整支援
Safari ✅ 自 11 版起支援

目前各大框架(React、Next.js、SvelteKit)也能直接載入 .wasm 模組,透過 WebAssembly.instantiate 或 Webpack/Vite 的 plugin 方式整合。


延伸:Wasm + Worker

在實務上,若你的 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 的地位

WebAssembly 不是要取代 JavaScript,而是讓 Web 平台能「平衡開發便利與效能極限」。

它的存在,讓瀏覽器不再只是顯示頁面的工具,而是真正的應用執行平台

JavaScript:靈活與互動。
WebAssembly:效能與計算。

當這兩者並肩而行,Web 才真正邁向「無邊界運算」的時代。


下一篇(Day 30),我們就要迎接最後的總結篇——回顧這 30 天,從 Canvas 到各式各樣的 Web API,瀏覽器到底變成了什麼樣的世界。🌍


👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 28 - WebSocket 讓瀏覽器與伺服器即時對話
下一篇
Day 30 - 完賽總結:從 Canvas 到各式各樣的 Web API 之旅 🎉
系列文
從 Canvas 到各式各樣的 Web API 之旅30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言