到目前為止,我們的 API 大致長這樣:
#[wasm_bindgen]
函式,直接跑影像管線;Uint8Array
回來,直接丟回 canvas;postMessage
回主執行緒。這個模式能用,但 API 層級有個痛點:同一套演算法核心,卻要在兩種語境裡寫兩次呼叫邏輯。同步呼叫 vs. Worker 呼叫,看起來像是兩種 API,但實際上只是封裝形式不同。
所謂「兩條船」:核心(Core)都用同一個,對外包裝兩層皮膚。
apply_pipeline()
/ apply_pipeline_fast()
就是正宮。worker.ts
裡,收到 { type:'run' }
→ 轉身呼叫正宮 → 再把結果傳回主執行緒。無論正宮還是小三,共用的都是同一套核心演算法。
WASM 算東西,Worker 只是換一張皮,演戲給不同場合看。
開發情境不同
契約保持一致
ops
陣列進去,Uint8Array
出來。錯誤訊息也一致
{ code, message }
。Rust 端不變,仍然:
#[wasm_bindgen]
pub fn apply_pipeline(input: &[u8], w: u32, h: u32, ops: &JsValue) -> Result<Vec<u8>, JsValue> {
// ... 核心邏輯 ...
}
前端可以:
// 正宮
const out = apply_pipeline(bytes, w, h, ops)
ctx.putImageData(new ImageData(new Uint8ClampedArray(out), w, h))
// 小三
worker.postMessage({ type:'run', w, h, ops, bytes })
worker.onmessage = ev => {
const { ok, bytes, error } = ev.data
if (ok) { /* set to canvas */ }
else { /* showError(error) */ }
}
兩者呼叫的人都是一樣的:ops
陣列進去,Uint8Array
出來。
「腳踏兩條船」不是亂搞,而是一種策略:
這樣我們就能享受「劈腿」的好處(沒大家現實生活都要做好男人好女人喔 (つд⊂)