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

SharedWorker

SharedWorker คือ Web Worker ที่ถูกแชร์ร่วมกันใน browsing context ทั้งหมด (tabs, windows, iframes) ที่มีต้นกำเนิดเดียวกัน ต่างจาก Dedicated Worker ที่มีอยู่เพียงสำหรับหน้าเดียว SharedWorker จะมีชีวิตอยู่จนกว่า tab ที่เชื่อมต่ออยู่ทั้งหมดจะปิด ให้คิดว่าเป็น “บริการ” น้ำหนักเบาภายใน browser — สามารถเก็บ state ที่แชร์ร่วมกัน ลดคำขอเครือข่ายที่ซ้ำกัน และซิงโครไนซ์ข้อมูลข้าม tab โดยไม่ต้องพึ่ง backend

Dedicated WorkerSharedWorker
Instance ต่อ tab?ใช่ — หนึ่งต่อหน้าไม่ — หนึ่งแชร์ร่วมกันทุก tab
Constructornew Worker(url)new SharedWorker(url)
การสื่อสารworker.postMessage โดยตรงworker.port.postMessage ผ่าน MessagePort
Worker รับ connect หรือไม่?ไม่ใช่ — event onconnect จะยิงทุกครั้งที่มี tab ใหม่
อายุการใช้งานผูกกับหน้าที่เป็นเจ้าของจนกว่า tab ที่เชื่อมต่อทั้งหมดจะปิด

มีขั้นตอนสำคัญสี่ขั้นตอนในการใช้งาน SharedWorker

ขั้นตอนที่ 1 — ในเธรดหลัก:

const worker = new SharedWorker('shared-worker.js');
worker.port.start(); // must call start() to activate the port
worker.port.postMessage('hello');
worker.port.onmessage = (e) => console.log(e.data);

ขั้นตอนที่ 2 — ใน worker (shared-worker.js):

const ports = [];
self.onconnect = (e) => {
const port = e.ports[0];
ports.push(port);
port.start();
port.onmessage = (ev) => {
// echo to all connected tabs
for (const p of ports) p.postMessage('echo: ' + ev.data);
};
};

พลังที่แท้จริงของ SharedWorker อยู่ที่การแชร์ state ข้าม tab การเปิด tab เดียวแทบไม่แสดงให้เห็นความสามารถนี้ — คุณต้องมีอย่างน้อยสอง tab จึงจะเห็นความแตกต่าง นั่นคือเหตุผลที่ตัวอย่างที่รันได้ด้านล่างเปิดใน StackBlitz ซึ่งคุณสามารถเปิดสองหน้าต่าง browser ที่ชี้ไปยัง URL เดียวกันได้

ตัวอย่างที่รันได้: ตัวนับแชร์ร่วมกันข้าม tab (StackBlitz)

หัวข้อที่มีชื่อว่า “ตัวอย่างที่รันได้: ตัวนับแชร์ร่วมกันข้าม tab (StackBlitz)”
SharedWorker

Needs multiple tabs / a SharedWorker context — open in StackBlitz to run.

ตัวเลือกBenefitCost
SharedWorker (instance เดียวทุก tab)ประหยัด memory, แชร์ state และ coordination ข้าม tab ได้ทันที (เช่น connection เดียวสำหรับหลาย tab)Debug ยากกว่า — DevTools ต้องเปิดแยกสำหรับ shared worker, และ historically iOS Safari ไม่รองรับหรือรองรับไม่สมบูรณ์
Dedicated Worker (instance ต่อ tab)รองรับ browser ครบทุกตัว, debug ง่ายเพราะผูกกับหน้าเดียวใช้ memory มากขึ้นเมื่อเปิดหลาย tab พร้อมกัน ไม่มี state ที่แชร์ร่วมกันในตัว
  • พึ่งพา SharedWorker บน iOS Safari โดยไม่มี fallback — support ของ SharedWorker บน iOS Safari ไม่แน่นอนในอดีต ควร feature-detect ด้วย typeof SharedWorker !== 'undefined' แล้ว fallback ไปใช้ Dedicated Worker หรือกลไกอื่น
  • ลืมเรียก port.start() — ทั้งฝั่งหน้าเว็บและฝั่ง worker ต้องเรียก port.start() ก่อน message ถึงจะไหลผ่าน MessagePort ไม่อย่างนั้น message จะถูก queue ค้างไว้เฉยๆ
  • คาดว่า onconnect จะยิงแค่ครั้งเดียวonconnect ยิงทุกครั้งที่มี tab ใหม่มาเชื่อมต่อ ต้อง push port ใหม่เข้า list ที่มีอยู่แทนที่จะ overwrite ไม่งั้น tab เก่าจะหลุดจากการสื่อสาร

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

Slack — ใช้ SharedWorker เพื่อรักษา WebSocket connection เดียวที่แชร์ร่วมกันทุก tab ที่เปิดอยู่ ลดจำนวน connection ไปยัง server และซิงค์สถานะ real-time ข้าม tab ได้ทันที

ระบบแดชบอร์ดหรือเครื่องมือ back-office ที่เปิดหลาย tab พร้อมกัน — ใช้ SharedWorker แชร์ token การยืนยันตัวตนและแคช API response เดียวกันข้าม tab เพื่อลดจำนวนคำขอไปยัง server

มี SharedWorker instance กี่ตัวเมื่อสาม tab บน origin เดียวกันทั้งหมดเรียก `new SharedWorker('sw.js')`?
event ใดที่ยิงใน script ของ SharedWorker เมื่อ tab ใหม่เชื่อมต่อ?
ทำไมจึงต้องเรียก `port.start()` ใน SharedWorker?
prop ใดที่ส่งให้ StorageRunner เพื่อเปิด demo SharedWorker ใน StackBlitz?