深度解析

WebAssembly 解析:它補上了什麼缺口,又有哪些局限

koboshiCo-founder
·3 分鐘閱讀
WebAssembly 解析:它補上了什麼缺口,又有哪些局限
概述

WebAssembly 不是要取代 JavaScript。它是一種精簡的二進位指令格式,讓瀏覽器以接近原生的效能執行 C、C++、Rust 等語言編譯出來的程式碼。本文會說明純網頁應用的限制、WebAssembly 解決了什麼、它真實的取捨、常見使用情境,以及為何沒有它,用戶端 HEIC 轉換就不可能實現。

將一張 HEIC 照片拖進瀏覽器轉換器。它是一種容器格式,內部保存著以 HEVC 編碼的圖像資料 —— 也就是 4K 影片所用的 H.265 壓縮格式。瀏覽器本身沒有內建 HEVC 解碼器,若要用 JavaScript 從頭寫一個,不只緩慢、脆弱,還會異常龐大。真正需要的是 libheif,由 strukturag 維護的 C++ 函式庫;WebAssembly 正是讓這個 C++ 解碼器能在瀏覽器分頁中執行的技術。

單是這個例子,就足以說明核心概念。WebAssembly 不是新的程式語言,也不是要取代 JavaScript。它是一種可攜的二進位指令格式,也是在瀏覽器中與 JavaScript 並行執行的沙箱化執行環境。

WebAssembly 究竟是什麼

WebAssembly(Wasm)是 W3C 標準。它定義了一種精簡的二進位指令格式,以及一套以堆疊為基礎的虛擬機器。通常你不會手寫 Wasm,而是從 C、C++、Rust、Go、Zig、C# 或越來越多其他語言編譯而來。產出的是一個 .wasm 模組,由瀏覽器下載、驗證,並在記憶體安全的沙箱中執行。

所有主流瀏覽器自 2017 年起就支援 WebAssembly。這種模組格式設計成:

  • 精簡:二進位格式,解析速度比等量的 JavaScript 原始碼更快。
  • 快速:由瀏覽器預先編譯為機器碼。
  • 安全:每個模組擁有獨立的線性記憶體,並進行邊界檢查。
  • 語言無關:任何能編譯成 Wasm 指令集的語言,都能在網頁上執行。

傳統網頁的局限

JavaScript 很適合寫使用者介面、網路請求和銜接程式碼。它是動態型別、具備垃圾回收機制,並以 JIT 編譯執行。這些特性讓它很有彈性,但面對大量運算時也變得難以預測。

垃圾回收停頓可能讓 UI 執行緒在動畫進行中卡住。JIT 預熱表示同一段程式碼在不同時刻可能以不同速度執行。至於數值或位元運算 —— 例如圖像解碼、影片編碼、密碼學、物理模擬、大型矩陣運算 —— JavaScript 通常比同樣邏輯用 C 或 Rust 編譯出來的版本慢上一個數量級。

另一個限制是生態系統的鎖定。數十年來的圖像、音訊、影片與科學運算函式庫都是以 C 和 C++ 寫成。要把這些能力帶到網頁上,用 JavaScript 重寫並不現實。

WebAssembly 為什麼存在

Wasm 的誕生是為了一次解決兩個問題:

  1. 讓現有的原生程式碼在瀏覽器中執行,不必用 JavaScript 重寫。
  2. 為網頁應用提供一個可預測的高效能執行層,負責 JavaScript 原本並不擅長處理的部分。

它明確是 JavaScript 的夥伴,而不是繼任者。DOM、網路堆疊和大多數 API 仍然由 JavaScript 掌管。Wasm 負責隔離的運算;JavaScript 負責協調。

WebAssembly 解決了什麼

  • CPU 密集型工作負載:圖像解碼、影片轉碼、物理運算、資料加密。
  • 可預測的效能:沒有垃圾回收器,也沒有 JIT 預熱曲線。
  • 程式碼複用:把 libheif、FFmpeg、SQLite、OpenCV 等經過實戰驗證的函式庫帶進瀏覽器。
  • 隱私:敏感資料可以在本地處理,不必上傳到伺服器。
  • 離線執行.wasm 模組下載完成後,執行時不需要再往返網路。

優點與缺點

面向優勢限制
效能數值與記憶體密集型任務可達接近原生的速度不會比原生更快;仍受瀏覽器與裝置限制
可攜性同一個模組可在任何瀏覽器與作業系統上執行需要 JavaScript 宿主才能操作 DOM 與大多數瀏覽器 API
安全性具備邊界檢查的沙箱化線性記憶體與任何瀏覽器程式碼一樣,可能受 Spectre 類型的旁道攻擊影響
生態系統可複用現有的 C/C++/Rust 程式碼庫與 JavaScript 互通會增加複雜度與開銷
啟動速度二進位格式解析快速首次載入時,模組下載與實例化可能很大

務實地說:Wasm 讓瀏覽器能夠執行過去做不到的工作,但它並未消除在使用者裝置上執行所帶來的限制。

常見使用情境

當網頁應用需要在本地進行大量運算時,WebAssembly 已經成為預設答案:

  • 圖像與影片編輯:Figma、Photopea 等工具使用 Wasm 進行渲染與特效處理。
  • 影片轉碼:FFmpeg.wasm 在瀏覽器中執行 FFmpeg,進行格式轉換。
  • 光學字元辨識:Tesseract.js 把 Tesseract OCR 引擎移植到 Wasm。
  • 遊戲:Unity、Godot 與 Unreal Engine 都能匯出為 Wasm,用於瀏覽器遊戲。
  • 資料分析:Pyodide 帶來 Python 與科學運算套件;sql.js 在瀏覽器中執行 SQLite。
  • 機器學習推論:ONNX Runtime Web 使用 Wasm 後端進行 CPU 推論。
  • CAD 與 3D 檢視器:過去只在桌機上執行的複雜幾何核心。
  • 密碼學:在用戶端執行雜湊、加密與零知識證明。

常見的 WebAssembly 函式庫

函式庫來源功能
heic-to透過 Emscripten 編譯的 libheif在瀏覽器中解碼 HEIC/HEIF 圖像,並轉換為 JPEG、PNG 或點陣圖。
FFmpeg.wasm透過 Emscripten 編譯的 FFmpeg完全在用戶端進行音訊/影片轉碼、重新封裝與濾鏡處理。
Tesseract.js透過 Emscripten 編譯的 Tesseract OCR在瀏覽器中辨識圖像內的文字。
sql.js透過 Emscripten 編譯的 SQLite在瀏覽器中以記憶體內檔案執行完整的 SQLite 資料庫引擎。
Pyodide透過 Emscripten 編譯的 CPython無需後端即可執行 Python 以及 NumPy、Pandas、SciPy 等套件。
ONNX Runtime Web透過 Emscripten 編譯的 ONNX Runtime在 CPU(Wasm)或 GPU(WebGL/WebGPU)上執行 ONNX 機器學習模型。

每個項目背後的模式都一樣:將成熟的原生專案編譯成 Wasm,再用 JavaScript API 包裝。這就是 WebAssembly 在實務中的價值。

為什麼線上 HEIC 轉 JPG/PNG/WebP 需要 WebAssembly

HEIC 是容器格式,不是編碼器(codec)。真正的圖像資料是以 HEVC 編碼,運算成本高且受專利限制。沒有任何瀏覽器內建網頁可使用的 HEVC 解碼器。伺服器端轉換是顯而易見的後備方案,但這需要上傳使用者的照片。

另一個做法是將 libheif —— 也就是桌面工具所用的同一個解碼器 —— 編譯成 WebAssembly。當你使用我們的 HEIC 轉 JPG 轉換器 時,解碼過程就在你的瀏覽器中進行:

  1. 透過讀取 ftyp box 簽章來驗證檔案。
  2. libheif Wasm 模組在本地解碼 HEVC 位元流。
  3. 解碼後的點陣圖被寫入 canvas,並匯出為 JPEG。

同一個模組也支援 HEIC 轉 PNG,可輸出保留透明度的無損圖像,以及 HEIC 轉 WebP,取得適合網頁使用的檔案大小。不需要上傳、不需要伺服器處理,第三方也看不到這張圖片。

這個流程之所以可行,正是因為 WebAssembly 能在瀏覽器中執行真正的圖像解碼器。單靠 JavaScript 無法在合理時間內解析 HEVC;上傳到伺服器又會違背隱私承諾。Wasm 是讓這一切成真的關鍵。

WebAssembly 的未來

Wasm 正逐漸走出瀏覽器。WebAssembly System Interface(WASI)定義了一個可攜的系統介面,讓 Wasm 模組能在伺服器、邊緣節點與 IoT 裝置上執行。Wasmtime、Wasmer 和 WasmEdge 等執行環境已經在瀏覽器之外的生產環境中部署。

Component Model 提案將讓 Wasm 模組暴露具型別的介面,並像函式庫一樣組合,讓 Rust 模組嵌入 Python 宿主或 Go 服務變得更簡單。WebAssembly GC 則為 Java、Kotlin 等受管理語言提供更好的支援。這些都不是為了取代瀏覽器中的 JavaScript —— 而是要讓 Wasm 成為一個通用且輕量的執行目標。

瀏覽器內部也看得出同樣的趨勢:更多原生能力移到使用者端、更多保護隱私的工具,以及越來越多過去只在桌機上執行的函式庫,現在能在分頁中運作。WebAssembly 不是使用者會注意到的亮眼功能,卻正逐漸成為讓複雜任務在網頁上順利執行的關鍵。

更多推薦閱讀