Belajar WebAssembly - Data & Binary Processing
Episode 13 of 23

Belajar WebAssembly - Data & Binary Processing

Menggunakan WebAssembly untuk pemrosesan data dan binary: codec, image/video transcoding, parse dan serialize data dengan serde, plus SIMD, AOT/JIT tier-up, dan caching WebAssembly.Module dengan compileStreaming

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Setelah di episode 12 kita melihat Wasm berperan di edge computing — pada episode ini kita kembali ke salah satu kasus penggunaannya yang paling nyata dan menguntungkan: pemrosesan data dan binary. Compress gambar, transcoding video, parsing format binary — semua pekerjaan yang membebani JavaScript kini bisa dijalankan secepat native di browser.

Mengapa Wasm unggul di sini? Karena workload ini bersifat komputasi intensif dan deterministic — sangat cocok untuk bytecode yang dikompilasi ke kode mesin. Satu modul codec yang ditulis dalam C bisa berjalan di browser, server, dan edge tanpa perubahan, dengan performa yang mendekati native. Ini bukan sekadar teori: seluruh industri (Figma, Google, 1Password) sudah membangun fitur di atas pola ini.

Codec: Kompresi dan Dekompresi

Contoh paling klasik adalah zlib — library kompresi C yang berumur puluhan tahun, dikompilasi ke Wasm:

Compile zlib ke Wasm (jalur C)
emcc -O2 -s EXPORTED_FUNCTIONS="[_compress2, _uncompress]" \
  -s ALLOW_MEMORY_GROWTH=1 zlib-*.c -o zlib.js

Hasilnya: modul zlib.wasm yang bisa dikompresi data secepat library native, tanpa server. Untuk file teks, JSON, atau HTML besar yang dikirim ke client, kompresi di sisi client bisa menghemat bandwidth secara signifikan.

JSKompresi string di browser
import { compress2, uncompress } from "./zlib.js"
 
const teks = "data berulang ".repeat(1000)
const compressed = compress2(new TextEncoder().encode(teks))
console.log("ukuran asli:", teks.length, "->", compressed.length)
 
const kembali = uncompress(compressed)
console.log(new TextDecoder().decode(kembali))

Image/Video Processing di Browser

Alur transcoding gambar biasanya: user memilih file → browser memprosesnya → hasil dikirim. Dengan Wasm, pemrosesan dilakukan lokal — cepat dan privasi terjaga karena data tidak meninggalkan perangkat.

Pola umum dengan canvas + memory sharing:

JSTranscoding gambar dengan wasm
const { instance } = await WebAssembly.instantiateStreaming(
  fetch("resize.wasm"),
)
 
async function proses(file) {
  const bitmap = await createImageBitmap(file)
 
  // tulis pixel ke linear memory wasm
  const memory = instance.exports.memory
  const buf = new Uint8Array(memory.buffer)
  const pixelData = await getPixelData(bitmap) // ImageData
  buf.set(pixelData, 0)
 
  // panggil resize di wasm (gambar keluar juga di memory)
  instance.exports.resize(0, bitmap.width, bitmap.height, 512, 512)
 
  // baca hasil & render ke canvas
  const hasil = new Uint8ClampedArray(memory.buffer, 0, 512 * 512 * 4)
  const canvas = document.getElementById("out")
  canvas.width = 512
  canvas.height = 512
  canvas.getContext("2d").putImageData(
    new ImageData(hasil, 512, 512), 0, 0,
  )
}

Inilah pola inti: pixel data masuk via memory linear, diproses di Wasm, hasil dibaca kembali — tidak ada serialisasi JSON yang boros.

Parse dan Serialize Binary dengan serde

Di dunia Rust, serde (serialization framework) bekerja mulus dengan wasm-bindgen. Kalian bisa parse format binary besar — parquet, protobuf, atau format custom — langsung di Wasm:

parse.rs
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
 
#[derive(Serialize, Deserialize)]
struct Transaksi {
    id: u64,
    nominal: f64,
    tag: String,
}
 
#[wasm_bindgen]
pub fn parse_transaksi(data: &[u8]) -> Result<JsValue, JsValue> {
    let t: Transaksi = serde_json::from_slice(data)
        .map_err(|e| JsValue::from_str(&e.to_string()))?;
    Ok(serde_wasm_bindgen::to_value(&t)
        .map_err(|e| JsValue::from_str(&e.to_string()))?)
}

serde_json::from_slice mem-parse 1 MB JSON jauh lebih cepat di Wasm daripada JSON.parse di JS untuk kasus skema kompleks. Untuk format binary (bincode, postcard), kecepatannya bahkan lebih tinggi — dan ukuran datanya lebih kecil.

Tip

Untuk parsing binary dengan volume sangat tinggi, pertimbangkan zero-copy: wasm-bindgen bisa bekerja langsung di atas Uint8Array tanpa menyalin, menggunakan pola boxed slice — mengurangi garbage collection dan mempercepat throughput 2-3x.

SIMD untuk Workload Numerik

SIMD (dari episode 9) adalah senjata utama data processing. Contoh nyata: memfilter array besar berdasarkan nilai:

simd.rs
#[wasm_bindgen]
pub fn threshold(data: &[f32], batas: f32) -> Vec<f32> {
    data.iter()
        .filter(|&&x| x > batas)
        .copied()
        .collect()
}

Compiler Rust dengan -O3 otomatis menerapkan SIMD pada loop seperti ini ketika fitur simd128 aktif — hasilnya percepatan signifikan untuk sinyal, audio, atau analitik real-time di browser.

AOT, JIT Tier-Up, dan Caching Module

Kompilasi JIT dan Tier-Up

Engine browser mengkompilasi Wasm dalam dua tahap:

  1. Baseline compiler — mulai eksekusi cepat (dalam milidetik setelah download).
  2. Optimizing compiler (tier-up) — fungsi yang sering dipanggil dikompilasi ulang dengan optimasi penuh saat runtime.

Konsekuensinya: jangan mengukur performa dari run pertama — beri waktu engine untuk "memanaskan" fungsi hot-path.

Caching WebAssembly.Module

Ini strategi paling praktis untuk aplikasi nyata. WebAssembly.Module bisa di-cache dan di-instansiasi ulang dengan sangat murah (instance bisa dibuat ratusan kali per detik):

JSCache module di Cache Storage
async function muatModul(url) {
  const cache = await caches.open("wasm-cache")
 
  let modul = await cache.match(url).then((r) => r?.arrayBuffer())
 
  if (modul) {
    return await WebAssembly.Module.instantiate(modul) // dari cache
  }
 
  const response = await fetch(url)
  const modulBaru = await WebAssembly.compileStreaming(response)
  await cache.put(url, new Response(
    await WebAssembly.Module.export(modulBaru) // ... serialisasi
  ))
  return modulBaru
}

Pola yang disederhanakan — intinya: kompilasi sekali, reuse berkali-kali. Kombinasi compileStreaming (kompilasi sambil download) + caching menghindari biaya kompilasi ulang pada kunjungan berikutnya.

Common Pitfalls

  • Menyalin data berlebihan — setiap kopi antara memory Wasm dan JS menghabiskan waktu; rancang agar data mengalir satu arah.
  • Uji dengan data nyata — benchmark hanya meyakinkan jika memakai skema dan ukuran data yang mirip produksi.
  • Mengabaikan tier-up — ukur performa setelah warm-up, bukan pada run pertama.
  • Lupa validasi input — data dari user (gambar, file) bisa berbahaya; pastikan modul punya guard ukuran sebelum diproses.

Warning

Jangan pernah mem-parse data untrusted dengan parser yang belum diuji terhadap input korup — modul Wasm bisa trap atau menghabiskan memory. Selalu batasi ukuran input dan lakukan fuzz testing (kita bahas di episode 14).

Penutup

Pada episode 13 ini, kalian telah memahami cara memakai WebAssembly untuk data & binary processing yang efisien.

Inti yang harus dibawa pulang:

  • Codec (zlib dll.) dan transcoding image/video adalah workload ideal Wasm di browser.
  • Parse/serialize dengan serde + wasm-bindgen menggantikan JSON.parse untuk data besar.
  • SIMD memberi percepatan 2-4x pada loop numerik; tier-up JIT butuh warm-up.
  • compileStreaming + caching WebAssembly.Module menghilangkan biaya kompilasi berulang.

Di episode 14 selanjutnya kita akan membahas testing & debuggingcargo test untuk target wasm, wasm-bindgen-test, browser testing dengan Playwright, plus wasm-tools print/dump, DWARF debugging, dan section name. Sampai jumpa di episode 14!

Belajar WebAssembly - Data & Binary Processing | Belajar Web Assembly