ข้ามไปยังเนื้อหา

ทำไมต้องใช้ Wasm? และรันที่ไหนได้บ้าง?

WebAssembly ไม่ได้เกิดขึ้นโดยบังเอิญ แต่ถูกออกแบบมาเพื่อแก้ปัญหาเฉพาะกลุ่มที่ JavaScript เพียงอย่างเดียวแก้ไม่ได้ การเข้าใจ ว่าทำไม Wasm ถึงมีอยู่ และ ที่ไหน ที่ Wasm รันได้ จะให้ mental model ที่คุณต้องใช้ตัดสินใจว่าเมื่อไหร่ควรหยิบ Wasm มาใช้

Wasm ถูกคอมไพล์เป็น binary กะทัดรัดก่อนที่จะถึง runtime engine ไม่ต้อง parse source text, tokenize หรือสร้าง AST เมื่อโหลด การคอมไพล์แบบ AOT หรือ JIT จาก binary format นั้นรวดเร็วและสร้าง machine code ใกล้เคียง native สำหรับงาน compute-intensive เช่น image processing, audio codec, cryptography, physics simulation ช่องว่างนี้วัดได้และมีนัยสำคัญ

ไฟล์ .wasm เพียงไฟล์เดียวรันเหมือนกันทุกที่: laptop x86-64, โทรศัพท์ ARM, embedded board RISC-V, browser, edge node ไม่มีขั้นตอน recompile สำหรับแต่ละ target architecture runtime ตรวจสอบและรัน binary ตาม instruction set ที่ระบุไว้อย่างดี

Wasm คือ target สำหรับการคอมไพล์ ไม่ใช่ภาษาที่คุณเขียนด้วยมือในการใช้งานจริง ซึ่งหมายความว่าคุณเลือกเครื่องมือที่เหมาะสมสำหรับงาน:

  • Rust — zero-cost abstraction, ไม่มี garbage collector, toolchain wasm-pack ที่ยอดเยี่ยม
  • C / C++ — native library ที่มีอยู่มานานหลายทศวรรษ, คอมไพล์ด้วย Emscripten
  • Go — รองรับ standard library ดี, ecosystem กำลังเติบโต
  • AssemblyScript — syntax คล้าย TypeScript ที่คอมไพล์ตรงไปยัง Wasm
  • Python — ผ่าน Pyodide ที่เป็น CPython เต็มรูปแบบที่คอมไพล์เป็น Wasm รันใน browser

Wasm รันใน sandbox ที่เข้มงวด module ไม่สามารถเข้าถึง memory, file system หรือ network ของ host ได้ เว้นแต่ host จะ provide ความสามารถเหล่านั้นอย่างชัดเจนในรูปแบบ import linear memory ถูกตรวจสอบขอบเขตทุกครั้งที่เข้าถึง ไม่มี ambient permission Wasm module เริ่มต้นโดยไม่มีอะไรและได้รับเฉพาะสิ่งที่จำเป็นเท่านั้น

บ้านหลักของ Wasm คือ browser ผ่าน WebAssembly JavaScript API หน้าเว็บโหลดไฟล์ .wasm binary, instantiate ด้วย WebAssembly.instantiate และเรียกฟังก์ชันที่ export มาโดยตรงจาก JavaScript

const response = await fetch('module.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {});
instance.exports.myFunction();

browser หลักทุกตัว ได้แก่ Chrome, Firefox, Safari, Edge ได้รองรับ Wasm เต็มรูปแบบตั้งแต่ปี 2017

Node.js เปิดเผย WebAssembly.* API เดียวกับ browser Deno และ Bun ก็ทำเช่นเดียวกัน Cloudflare Workers และ Fastly Compute รองรับ Wasm module โดยกำเนิด ซึ่งหมายความว่าคุณสามารถ deploy binary เดิมไปยัง browser และ edge ได้โดยไม่ต้องเปลี่ยนแปลงอะไร

WebAssembly System Interface (WASI) คือ ABI มาตรฐานที่ให้ Wasm code รันนอก browser ด้วยการเข้าถึง OS capabilities อย่างควบคุม ไม่ว่าจะเป็น file, socket, clock, random โดยไม่ต้องมี JavaScript host เลย runtime อย่าง wasmtime และ wasmer implement WASI ทำให้คุณรันไฟล์ .wasm เป็น standalone process ได้

Sandboxing ของ Wasm ทำให้เหมาะกับ plugin architecture อย่างยิ่ง เครื่องมืออย่าง Extism และ embedded wasmtime ให้แอปพลิเคชันโหลด Wasm plugin ที่ไม่น่าไว้ใจ, expose API surface ที่ควบคุมได้ และบังคับใช้ข้อจำกัด memory และ capability ที่เข้มงวด ทั้งหมดนี้โดยไม่ต้องเปิด process แยกต่างหาก

Wasm ไม่ได้แทน JavaScript DOM, event handling, fetch และ web platform API ส่วนใหญ่เข้าถึงได้เฉพาะจาก JavaScript pattern ในทางปฏิบัติคือการแบ่งงาน: เก็บ IO, event และการจัดการ DOM ไว้ใน JavaScript และส่งงาน algorithm ที่ใช้ CPU หนักไปให้ Wasm module

ตัวเลือกBenefitCost
ใช้ Wasm สำหรับ compute pathความเร็วใกล้ native, portable ไปได้ทั้ง browser, server, edge, WASI runtime โดยไม่ต้อง recompileเพิ่ม bundle size จาก binary + JS glue code สำหรับ marshal ข้อมูลข้าม boundary
ใช้ JavaScript ล้วนทุกที่debugging tooling mature เต็มที่ (breakpoint, source map, profiler) และ ecosystem ใหญ่ไม่ portable เท่าในแง่ raw compute performance และไม่มี sandbox ระดับ memory แบบ Wasm
  • เห็นว่า Wasm “เร็วกว่า native เกือบเท่า” แล้วสรุปว่าเร็วกว่า JavaScript เสมอในทุก workload ทั้งที่ JS engine สมัยใหม่ optimize hot loop ได้ดีมากเช่นกัน
  • เลือกคอมไพล์ทั้งแอปพลิเคชันไปเป็น Wasm ตั้งแต่ต้น แทนที่จะดูจาก 4 เหตุผล (ความเร็ว, portability, การเลือกภาษา, ความปลอดภัย) ว่าจริงๆ แล้วมีแค่บาง module เช่น codec หรือ physics engine ที่ควรเป็น Wasm
  • deploy Wasm module เล็กๆ ไปยัง edge หรือ WASI runtime โดยไม่คำนึงถึง cold-start cost ของการ compile และ instantiate ซึ่งอาจสำคัญมากกว่าความเร็วในการ execute เมื่อ module ถูกเรียกไม่บ่อย

💡 ตัวอย่างจากของจริง

Adobe ใช้ Wasm พอร์ต Photoshop C++ codebase ทั้งก้อนมารันใน browser เป็น Photoshop Web โดยยังคง algorithm การประมวลผลภาพเดิมไว้ทั้งหมด

Google Earth ใช้ Wasm รัน C++ rendering engine เดิมใน browser ได้โดยไม่ต้องเขียนใหม่เป็น JavaScript ตรงกับเหตุผลเรื่อง portability และความเร็วที่กล่าวถึงในบทนี้

ข้อใดต่อไปนี้ไม่ใช่เหตุผลหลักในการใช้ WebAssembly?
WASI ย่อมาจากอะไร?
ข้อใดอธิบาย Wasm และ JavaScript ใน browser ได้ดีที่สุด?