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

Dedicated Web Workers

new Worker(url) รับ URL ที่ชี้ไปยังไฟล์ JavaScript browser จะดาวน์โหลดไฟล์นั้นและรันในเธรดพื้นหลังแยกต่างหาก ในบทเรียนเหล่านี้แทนที่จะต้อง host ไฟล์แยก เราจะสร้าง URL แบบ on-the-fly จาก Blob ซึ่งทำให้ทุกอย่างอยู่ในที่เดียวและรันได้ทันที

// worker.js (separate file)
self.onmessage = function(e) {
const result = heavyCompute(e.data);
self.postMessage(result);
};
// main.js
const worker = new Worker('/worker.js');
worker.onmessage = function(e) { console.log('result:', e.data); };
worker.postMessage(inputData);
  • worker.postMessage(data) — ส่งข้อมูลไปยัง worker จาก main thread
  • worker.onmessage = fn — รับข้อมูลจาก worker บน main thread
  • self.onmessage = fn — (ภายใน worker) รับข้อมูลจาก main thread
  • self.postMessage(data) — (ภายใน worker) ส่งผลลัพธ์กลับไปยัง main thread
  • worker.terminate() — หยุด worker ทันทีจาก main thread โดย worker จะไม่ได้รับการแจ้งเตือนใดๆ

แทนที่จะใช้ไฟล์แยก คุณสามารถกำหนด worker source เป็น string ห่อด้วย Blob แล้วแปลงเป็น object URL ด้วย URL.createObjectURL URL ที่ได้จะมีรูปแบบ blob:https://example.com/uuid และทำงานเหมือน URL ของไฟล์ที่ host ไว้จริงๆ เมื่อไม่ต้องการใช้ worker แล้ว ให้เรียก URL.revokeObjectURL(url) เพื่อคืน memory

Worker ด้านล่างจะรวมจำนวนเต็มตั้งแต่ 1 ถึง N ด้วย N = 1,000,000 ที่เป็น loop ที่ใช้เวลาพอสมควร หากรันบน main thread โดยตรงจะทำให้ UI ค้างชั่วขณะ — แต่นี่รันอยู่บน background thread แทน

Browser Storage
ตัวเลือกBenefitCost
ประมวลผลใน Web Workerได้ true parallelism เธรดพื้นหลังแยกจาก main thread ทำให้ UI ไม่ค้างระหว่างงานหนักต้นทุนการสื่อสารผ่าน postMessage (structured clone) และ overhead ของการสร้าง/ทำลาย worker
ประมวลผลบน main thread โดยตรงเรียบง่าย เข้าถึง DOM ได้ทันที ไม่มีต้นทุนการสื่อสารข้ามเธรดงานหนักบล็อก UI thread ทำให้หน้าเว็บค้างหรือ frame drop
Inline worker ผ่าน Blob URLไม่ต้อง host ไฟล์แยก รวมโค้ดไว้ที่เดียว deploy ง่ายDebug ยากกว่าไฟล์จริงเพราะไม่มี source map/breakpoint ที่ตรงไปตรงมา
  • คาดว่า worker เข้าถึง DOM ได้ — worker ไม่มี window, document หรือ DOM API ใดๆ เลย เป็นความเข้าใจผิดที่พบบ่อยที่สุดของมือใหม่ ต้อง postMessage ผลลัพธ์กลับมาให้ main thread จัดการ DOM แทน
  • ลืมเรียก worker.terminate() — worker ที่ยังไม่ terminate จะค้างอยู่ใน memory และกิน CPU ต่อไปแม้งานจะเสร็จแล้ว ทำให้เกิด memory leak โดยเฉพาะถ้าสร้าง worker ใหม่ซ้ำๆ
  • ใช้ worker กับงานสั้นๆ ที่ใช้เวลาน้อยกว่า 2-3 ms — ต้นทุนของการสร้าง worker และ postMessage ไป-กลับสูงกว่าประโยชน์ที่ได้ ควรใช้ worker เฉพาะงานที่ใช้เวลานานพอจะคุ้มกับ overhead

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

Figma — รัน rendering และการคำนวณ geometry ที่หนักหน่วงบน Web Worker แยกจาก main thread เพื่อให้ canvas ยังคง responsive ระหว่างที่ผู้ใช้แก้ไข design

Squoosh (เครื่องมือบีบอัดภาพของ Google) — รัน codec การบีบอัดภาพ (เช่น MozJPEG, WebP) ทั้งหมดใน Web Worker เพื่อไม่ให้ UI ค้างระหว่างประมวลผลไฟล์ขนาดใหญ่

identifier ใดที่อ้างถึง global scope ภายใน Web Worker?
worker.terminate() ทำอะไร?
เหตุใดในบทเรียนนี้จึงใช้ URL.createObjectURL(new Blob([src]))?