`Shared Worker` ใน TypeScript
บทความนี้อธิบายเกี่ยวกับ Shared Worker
ใน TypeScript
เราจะอธิบายอย่างละเอียดว่า Shared Worker ทำงานอย่างไร และวิธีใช้งานจริง พร้อมตัวอย่างโค้ด TypeScript
YouTube Video
Shared Worker
ใน TypeScript
Shared Worker
คือ กระบวนการเวิร์กเกอร์เดียวที่ถูกแชร์ร่วมกันระหว่างหลายแท็บ หน้าต่าง และ iframe บนต้นทาง (origin) เดียวกัน ด้วยสิ่งนี้ คุณสามารถจัดการสถานะและทรัพยากรร่วมกันข้ามหลายแท็บของเบราว์เซอร์ได้
ตัวอย่างเช่น คุณสามารถทำ การแชร์การเชื่อมต่อ WebSocket, แคชและการประมวลผลคิวที่ซิงก์กันข้ามแท็บ, และ การกีดกันกันพร้อมกัน (mutual exclusion) ได้อย่างมีประสิทธิภาพ
แตกต่างจาก Dedicated Worker
ตรงที่ Shared Worker
รับ MessagePort
หลายตัวผ่านเหตุการณ์ onconnect
และสามารถมัลติเพล็กซ์การสื่อสารกับไคลเอนต์หลายรายได้
กรณีที่ควรเลือกใช้ Shared Worker
ในกรณีต่อไปนี้ การใช้ Shared Worker
เป็นทางเลือกที่เหมาะสม
- เมื่อคุณต้องการสถานะร่วมกันหรือการทำ mutual exclusion ข้ามแท็บ
- เมื่อคุณต้องการแชร์การเชื่อมต่อ WebSocket เดียว หรือการเข้าถึง IndexedDB
- เมื่อคุณต้องการแจ้งเตือนทุกแท็บ (บรอดแคสต์)
- เมื่อคุณต้องการรวมศูนย์งานประมวลผลหนักเพื่อประหยัดทรัพยากร
ในทางกลับกัน ในกรณีต่อไปนี้ แนวทางอื่นจะเหมาะสมกว่า
- เมื่อคุณต้องการการควบคุมแคชหรือการรองรับออฟไลน์ คุณสามารถใช้
Service Worker
ได้ - สำหรับงานประมวลผลหนักที่จำกัดอยู่ในแท็บเดียว คุณสามารถใช้
Dedicated Worker
ได้
ขั้นตอนการนำไปใช้สำหรับ Shared Worker
ที่นี่ เราจะลงมือทำสิ่งต่อไปนี้แบบเป็นขั้นเป็นตอนด้วย TypeScript
- โปรโตคอลข้อความที่ปลอดภัยตามชนิดข้อมูล (type-safe)
- คำขอ/คำตอบ (RPC) ที่อิงกับ Promise
- บรอดแคสต์ไปยังทุกแท็บ
- ฮาร์ตบีตและการเคลียร์ไคลเอนต์
การตั้งค่าสภาพแวดล้อม
สร้างการกำหนดค่าเพื่อคอมไพล์ไฟล์ซอร์สแต่ละไฟล์ที่ใช้ Shared Worker
1{
2 "compilerOptions": {
3 "target": "ES2020",
4 "module": "ES2020",
5 "lib": ["ES2020", "dom", "WebWorker"],
6 "moduleResolution": "Bundler",
7 "strict": true,
8 "noEmitOnError": true,
9 "outDir": "out",
10 "skipLibCheck": true
11 },
12 "include": ["src"]
13}
- ใน
tsconfig-src.json
ให้เปิดใช้คำนิยามชนิดของ DOM และ Web Worker เพื่อให้โค้ดถูกคอมไพล์ได้อย่างปลอดภัย
การกำหนดโปรโตคอลของข้อความ
พื้นฐานของการสื่อสารคือ ข้อตกลงข้อความที่มีชนิดข้อมูลกำกับ การกำหนดสิ่งนี้ล่วงหน้าทำให้การสื่อสารหลังจากนั้นปลอดภัยและขยายต่อได้ง่าย
1// worker-protocol.ts
2// Define discriminated unions for structured messages
3
4export type RequestAction =
5 | { type: 'ping' }
6 | { type: 'echo'; payload: string }
7 | { type: 'getTime' }
8 | { type: 'set'; key: string; value: unknown }
9 | { type: 'get'; key: string }
10 | { type: 'broadcast'; channel: string; payload: unknown }
11 | { type: 'lock.acquire'; key: string; timeoutMs?: number }
12 | { type: 'lock.release'; key: string };
RequestAction
เป็น discriminated union (tagged union) ที่แทนประเภทของคำขอที่ส่งไปยัง worker และกำหนดการดำเนินการเช่นping
,get
, และbroadcast
1export interface RequestMessage {
2 kind: 'request';
3 id: string;
4 from: string;
5 action: RequestAction;
6}
RequestMessage
กำหนดโครงสร้างของข้อความคำขอที่ส่งจากไคลเอนต์ไปยังเวิร์กเกอร์
1export interface ResponseMessage {
2 kind: 'response';
3 id: string;
4 ok: boolean;
5 result?: unknown;
6 error?: string;
7}
ResponseMessage
กำหนดโครงสร้างของข้อความตอบกลับที่ส่งคืนจากเวิร์กเกอร์ไปยังไคลเอนต์
1export interface BroadcastMessage {
2 kind: 'broadcast';
3 channel: string;
4 payload: unknown;
5 from: string;
6}
BroadcastMessage
กำหนดโครงสร้างของข้อความกระจายสัญญาณที่เวิร์กเกอร์ส่งไปยังไคลเอนต์อื่น
1export type WorkerInMessage =
2 | RequestMessage
3 | { kind: 'heartbeat'; from: string }
4 | { kind: 'bye'; from: string };
WorkerInMessage
เป็นชนิดข้อมูลที่แทนข้อความทั้งหมดที่เวิร์กเกอร์ได้รับ เช่น คำขอ ฮาร์ทบีต และการแจ้งเตือนการตัดการเชื่อมต่อ
1export type WorkerOutMessage = ResponseMessage | BroadcastMessage;
WorkerOutMessage
เป็นชนิดข้อมูลที่แทนข้อความตอบกลับหรือข้อความกระจายที่เวิร์กเกอร์ส่งไปยังไคลเอนต์
1export const randomId = () => Math.random().toString(36).slice(2);
randomId
เป็นฟังก์ชันที่สร้างสตริงอักษร-ตัวเลขแบบสุ่มเพื่อใช้เป็นรหัสข้อความและสิ่งที่คล้ายกัน
การอิมพลีเมนต์ Shared Worker
ใน shared-worker.ts
ทำการลงทะเบียนแท็บที่เชื่อมต่อเข้ามาผ่านเหตุการณ์ onconnect
และจัดการข้อความ
1// shared-worker.ts
2/// <reference lib="webworker" />
- ไดเรกทีฟนี้สั่งให้ TypeScript โหลดคำนิยามชนิดสำหรับ Web Workers
1import {
2 WorkerInMessage,
3 WorkerOutMessage,
4 RequestMessage,
5 ResponseMessage,
6} from './worker-protocol.js';
- นำเข้าคำนิยามชนิดที่ใช้สำหรับการสื่อสารกับเวิร์กเกอร์
1export default {};
2declare const self: SharedWorkerGlobalScope;
- ประกาศอย่างชัดเจนว่า
self
คือขอบเขตระดับโกลบอลของShared Worker
1type Client = {
2 id: string;
3 port: MessagePort;
4 lastBeat: number;
5};
Client
เป็นชนิดข้อมูลที่แทนตัวระบุของไคลเอนต์แต่ละราย พอร์ตสื่อสาร และตราประทับเวลาของฮาร์ทบีตล่าสุด
1const clients = new Map<string, Client>();
2const kv = new Map<string, unknown>();
3const locks = new Map<string, string>();
4const HEARTBEAT_TIMEOUT = 30_000;
- จัดการรายชื่อไคลเอนต์ที่เชื่อมต่ออยู่ สโตร์แบบคีย์-ค่า สถานะการล็อก และระยะเวลาไทม์เอาต์
1function send(port: MessagePort, msg: WorkerOutMessage) {
2 port.postMessage(msg);
3}
send
เป็นฟังก์ชันอรรถประโยชน์ที่ส่งข้อความไปยังพอร์ตที่ระบุ
1function respond(req: RequestMessage, ok: boolean, result?: unknown, error?: string): ResponseMessage {
2 return { kind: 'response', id: req.id, ok, result, error };
3}
respond
สร้างข้อความตอบกลับสำหรับคำขอ
1function broadcast(from: string, channel: string, payload: unknown) {
2 for (const [id, c] of clients) {
3 send(c.port, { kind: 'broadcast', channel, payload, from });
4 }
5}
broadcast
ส่งข้อความบนช่องสัญญาณที่ระบุไปยังไคลเอนต์ทั้งหมด
1function handleRequest(clientId: string, port: MessagePort, req: RequestMessage) {
handleRequest
ประมวลผลคำขอที่เข้ามาตามชนิด และส่งผลลัพธ์กลับไปยังไคลเอนต์
1 const { action } = req;
2 try {
3 switch (action.type) {
4 case 'ping':
5 send(port, respond(req, true, 'pong'));
6 break;
7 case 'echo':
8 send(port, respond(req, true, action.payload));
9 break;
10 case 'getTime':
11 send(port, respond(req, true, new Date().toISOString()));
12 break;
13 case 'set':
14 kv.set(action.key, action.value);
15 send(port, respond(req, true, true));
16 break;
17 case 'get':
18 send(port, respond(req, true, kv.get(action.key)));
19 break;
20 case 'broadcast':
21 broadcast(clientId, action.channel, action.payload);
22 send(port, respond(req, true, true));
23 break;
- ในโค้ดนี้ จะจัดการการส่งและรับข้อความ การดึงและบันทึกข้อมูล และการบรอดแคสต์ ตามประเภทของคำขอที่ได้รับ
1 case 'lock.acquire': {
2 const owner = locks.get(action.key);
3 if (!owner) {
4 locks.set(action.key, clientId);
5 send(port, respond(req, true, { owner: clientId }));
6 } else if (owner === clientId) {
7 send(port, respond(req, true, { owner }));
8 } else {
9 const start = Date.now();
10 const tryWait = () => {
11 const current = locks.get(action.key);
12 if (!current) {
13 locks.set(action.key, clientId);
14 send(port, respond(req, true, { owner: clientId }));
15 } else if ((action.timeoutMs ?? 5000) < Date.now() - start) {
16 send(port, respond(req, false, undefined, 'lock-timeout'));
17 } else {
18 setTimeout(tryWait, 25);
19 }
20 };
21 tryWait();
22 }
23 break;
24 }
- โค้ดนี้ทำหน้าที่ให้ไคลเอนต์สามารถขอล็อกสำหรับคีย์ที่ระบุได้ หากล็อกยังไม่มีผู้ถืออยู่ จะได้รับทันที; หากไคลเอนต์เดียวกันร้องขออีกครั้ง คำขอนั้นก็ถือว่าสำเร็จเช่นกัน หากมีไคลเอนต์รายอื่นถือครองล็อกอยู่แล้ว ระบบจะลองใหม่ทุกๆ 25 มิลลิวินาทีจนกว่าจะปล่อยล็อก และหากเกินเวลาที่กำหนด (ค่าเริ่มต้น 5 วินาที) จะตอบกลับด้วยข้อผิดพลาด
1 case 'lock.release':
2 if (locks.get(action.key) === clientId) {
3 locks.delete(action.key);
4 send(port, respond(req, true, true));
5 } else {
6 send(port, respond(req, false, undefined, 'not-owner'));
7 }
8 break;
9 default:
10 send(port, respond(req, false, undefined, 'unknown-action'));
11 }
12 } catch (e: any) {
13 send(port, respond(req, false, undefined, e?.message ?? 'error'));
14 }
15}
- โค้ดนี้จะปล่อยล็อกที่ไคลเอนต์ครอบครองอยู่ และส่งคืนการตอบสนองแบบข้อผิดพลาดหากไคลเอนต์ไม่มีสิทธิ์หรือการกระทำนั้นไม่เป็นที่รู้จัก
1function handleInMessage(c: Client, msg: WorkerInMessage) {
2 if (msg.kind === 'heartbeat') {
3 c.lastBeat = Date.now();
4 } else if (msg.kind === 'bye') {
5 cleanupClient(msg.from);
6 } else if (msg.kind === 'request') {
7 handleRequest(c.id, c.port, msg);
8 }
9}
handleInMessage
แยกวิเคราะห์ข้อความที่ได้รับจากไคลเอนต์ และจัดการคำขอและฮาร์ทบีต
1function cleanupClient(clientId: string) {
2 for (const [key, owner] of locks) {
3 if (owner === clientId) locks.delete(key);
4 }
5 clients.delete(clientId);
6}
cleanupClient
ลบไคลเอนต์ที่ตัดการเชื่อมต่อออกจากรีจิสทรีและสถานะการล็อก
1setInterval(() => {
2 const now = Date.now();
3 for (const [id, c] of clients) {
4 if (now - c.lastBeat > HEARTBEAT_TIMEOUT) cleanupClient(id);
5 }
6}, 10_000);
- ใช้
setInterval
เพื่อตรวจสอบฮาร์ทบีตของไคลเอนต์ทั้งหมดเป็นระยะ และเคลียร์การเชื่อมต่อที่หมดเวลา
1self.onconnect = (e: MessageEvent) => {
2 const port = (e.ports && e.ports[0]) as MessagePort;
3 const clientId = crypto.randomUUID?.() ?? Math.random().toString(36).slice(2);
4 const client: Client = { id: clientId, port, lastBeat: Date.now() };
5 clients.set(clientId, client);
6
7 port.addEventListener('message', (ev) => handleInMessage(client, ev.data as WorkerInMessage));
8 send(port, { kind: 'broadcast', channel: 'system', payload: { hello: true, clientId }, from: 'worker' });
9 port.start();
10};
-
onconnect
จะถูกเรียกเมื่อแท็บหรือหน้าใหม่เชื่อมต่อกับShared Worker
โดยลงทะเบียนไคลเอนต์และเริ่มการสื่อสาร -
ตลอดทั้งไฟล์นี้ ได้มีการนำกลไกพื้นฐานของ
Shared Worker
ที่ทำให้สามารถจัดการสถานะร่วมและการสื่อสารข้ามหลายแท็บของเบราว์เซอร์ มาใช้งาน
ตัวห่อฝั่งไคลเอนต์ (RPC)
ถัดไป สร้างไคลเอนต์ RPC ที่อิงกับ Promise
1// shared-worker-client.ts
2import {
3 RequestAction,
4 RequestMessage,
5 WorkerOutMessage,
6 randomId
7} from './worker-protocol.js';
- นำเข้าคำนิยามชนิดและฟังก์ชันอรรถประโยชน์ที่ใช้สำหรับการสื่อสารกับเวิร์กเกอร์
1export type BroadcastHandler = (msg: {
2 channel: string;
3 payload: unknown;
4 from: string
5}) => void;
- ที่นี่เรากำหนดชนิดของฟังก์ชันคอลแบ็กที่ทำงานเมื่อได้รับข้อความกระจาย
1export class SharedWorkerClient {
SharedWorkerClient
เป็นคลาสไคลเอนต์ที่สื่อสารกับShared Worker
โดยส่งคำขอและจัดการคำตอบ
1 private worker: SharedWorker;
2 private port: MessagePort;
3 private pending = new Map<string, {
4 resolve: (v: any) => void;
5 reject: (e: any) => void
6 }>();
- ตัวแปรเหล่านี้คืออินสแตนซ์ของเวิร์กเกอร์ พอร์ตสื่อสารกับเวิร์กเกอร์ และแผนที่ที่ติดตามคำขอที่รอการตอบกลับ
1 private clientId = randomId();
2 private heartbeatTimer?: number;
3 private onBroadcast?: BroadcastHandler;
- ตัวแปรเหล่านี้เก็บตัวระบุไคลเอนต์ ตัวตั้งเวลาในการส่งฮาร์ทบีต และฮ্যান্ডเลอร์สำหรับรับข้อความกระจาย
1 constructor(url: URL, name = 'app-shared', onBroadcast?: BroadcastHandler) {
2 this.worker = new SharedWorker(url, { name, type: 'module' as any });
3 this.port = this.worker.port;
4 this.onBroadcast = onBroadcast;
- ในคอนสตรัคเตอร์ จะเริ่มต้นการเชื่อมต่อกับ
Shared Worker
และตั้งค่าตัวดักฟังข้อความรวมถึงการส่งฮาร์ทบีต
1 this.port.addEventListener('message', (ev) => {
2 const msg = ev.data as WorkerOutMessage;
3 if (msg.kind === 'response') {
4 const p = this.pending.get(msg.id);
5 if (p) {
6 this.pending.delete(msg.id);
7 msg.ok ? p.resolve(msg.result) : p.reject(new Error(msg.error || 'error'));
8 }
9 } else if (msg.kind === 'broadcast') {
10 this.onBroadcast?.(msg);
11 }
12 });
13 this.port.start();
- ที่นี่จะรับข้อความจากเวิร์กเกอร์และจัดการกับคำตอบหรือการกระจายข้อความ
1 this.heartbeatTimer = window.setInterval(() => {
2 this.port.postMessage({ kind: 'heartbeat', from: this.clientId });
3 }, 10_000);
- ส่งข้อความฮาร์ทบีตเป็นระยะเพื่อคงการเชื่อมต่อให้ทำงานต่อเนื่อง
1 window.addEventListener('beforeunload', () => {
2 try {
3 this.port.postMessage({ kind: 'bye', from: this.clientId });
4 } catch {}
5 if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
6 });
7 }
- ส่งการแจ้งเตือนการตัดการเชื่อมต่อไปยังเวิร์กเกอร์ก่อนที่หน้าต่างจะปิด
1 request<T = unknown>(action: RequestAction): Promise<T> {
2 const id = randomId();
3 return new Promise<T>((resolve, reject) => {
4 this.pending.set(id, { resolve, reject });
5 this.port.postMessage({ kind: 'request', id, from: this.clientId, action });
6 });
7 }
- เมธอด
request
ส่งแอ็กชันที่ระบุไปยังเวิร์กเกอร์และรับผลลัพธ์เป็นPromise
1 ping() {
2 return this.request<string>({ type: 'ping' });
3 }
4 echo(payload: string) {
5 return this.request<string>({ type: 'echo', payload });
6 }
7 getTime() {
8 return this.request<string>({ type: 'getTime' });
9 }
- เมธอดอรรถประโยชน์เหล่านี้ใช้สำหรับทดสอบการสื่อสารพื้นฐานและดึงเวลาปัจจุบัน
1 set(key: string, value: unknown) {
2 return this.request<boolean>({ type: 'set', key, value });
3 }
4 get<T = unknown>(key: string) {
5 return this.request<T>({ type: 'get', key });
6 }
- เมธอดเหล่านี้ใช้สำหรับจัดเก็บและเรียกข้อมูลคู่คีย์-ค่า
1 broadcast(channel: string, payload: unknown) {
2 return this.request<boolean>({ type: 'broadcast', channel, payload });
3 }
- นี่คือเมธอดที่ส่งข้อความกระจายไปยังไคลเอนต์อื่นผ่านเวิร์กเกอร์
1 lockAcquire(key: string, timeoutMs?: number) {
2 return this.request<{ owner: string }>({ type: 'lock.acquire', key, timeoutMs });
3 }
4 lockRelease(key: string) {
5 return this.request<boolean>({ type: 'lock.release', key });
6 }
7}
- เมธอดเหล่านี้ใช้ขอและปล่อยล็อกเพื่อให้เกิด mutual exclusion บนทรัพยากรร่วม
- ตลอดทั้งไฟล์นี้ ได้มีการสร้าง API ฝั่งไคลเอนต์สำหรับการสื่อสารแบบอะซิงโครนัสที่ปลอดภัยจากแต่ละแท็บของเบราว์เซอร์ไปยัง Shared Worker
ตัวอย่างการใช้งาน
ใน demo.ts
เราใช้คลาส SharedWorkerClient
ที่สร้างไว้ก่อนหน้านี้และตรวจสอบพฤติกรรมการทำงานของมัน โดยจะรันฟังก์ชันต่างๆ ตามลำดับ รวมถึงการทดสอบการสื่อสาร การอ่านและเขียนข้อมูล การบรอดแคสต์ และการจัดการล็อก
1// demo.ts
2import { SharedWorkerClient } from './shared-worker-client.js';
3
4const client = new SharedWorkerClient(new URL('./shared-worker.js', import.meta.url), 'app-shared', (b) => {
5 console.log('[BROADCAST]', b.channel, JSON.stringify(b.payload));
6});
7
8async function demo() {
9 console.log('ping:', await client.ping());
10 console.log('echo:', await client.echo('hello'));
11 console.log('time:', await client.getTime());
12
13 // Counter update
14 await client.set('counter', (await client.get<number>('counter')) ?? 0);
15 const c1 = await client.get<number>('counter');
16 await client.set('counter', (c1 ?? 0) + 1);
17 console.log('counter:', await client.get<number>('counter'));
18
19 // Broadcast test
20 await client.broadcast('notify', { msg: 'Counter updated' });
21
22 // Lock test
23 const key = 'critical';
24 console.log(`[lock] Trying to acquire lock: "${key}"`);
25 const lockResult = await client.lockAcquire(key, 2000);
26 console.log(`[lock] Lock acquired for key "${key}":`, lockResult);
27
28 try {
29 console.log(`[lock] Simulating critical section for key "${key}"...`);
30 await new Promise((r) => setTimeout(r, 250));
31 console.log(`[lock] Critical section completed for key "${key}"`);
32 } finally {
33 console.log(`[lock] Releasing lock: "${key}"`);
34 const releaseResult = await client.lockRelease(key);
35 console.log(`[lock] Lock released for key "${key}":`, releaseResult);
36 }
37}
38
39demo().catch(console.error);
- โค้ดนี้เป็นเดโมที่ใช้
Shared Worker
เพื่อแบ่งปันและซิงโครไนซ์ข้อมูลและสถานะข้ามหลายแท็บของเบราว์เซอร์ ด้วยการใช้การสื่อสารแบบอิงข้อความ คุณสามารถแลกเปลี่ยนข้อความแบบอะซิงโครนัสได้อย่างปลอดภัยด้วยการเชื่อมโยงกันอย่างหลวม ช่วยให้ง่ายต่อการจัดการการสื่อสารระหว่างบริบทที่แตกต่างกัน นอกจากนี้ ด้วยการใช้ RPC ยังช่วยยกระดับการสื่อสารกับเวิร์กเกอร์ให้อยู่ในรูปแบบที่เป็นนามธรรม คล้ายการเรียกเมธอด ทำให้ง่ายต่อการบำรุงรักษาและอ่านเข้าใจ
การทดสอบใน HTML
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>Shared Worker Demo</title>
7</head>
8<body>
9 <h1>SharedWorker Demo</h1>
10 <p>Open the browser console to see the output.</p>
11
12 <script type="module">
13 import './demo.js';
14 </script>
15</body>
16</html>
ข้อพิจารณาด้านการออกแบบและการปฏิบัติงาน
ในการออกแบบและการดำเนินงาน หากคำนึงถึงประเด็นต่อไปนี้จะช่วยให้คุณสร้างระบบที่แข็งแกร่งและขยายต่อได้มากขึ้น
- คุณสามารถใช้ discriminated union (tagged union) ที่อนุญาตให้แยกแขนงตาม
kind
หรือtype
- ใช้ correlation ID เพื่อจับคู่คำขอกับคำตอบให้ถูกต้อง
- ฮาร์ทบีตและการทำความสะอาดอัตโนมัติ สามารถป้องกันล็อกที่ถูกทิ้งค้างได้
- นำ versioning มาใช้เพื่อรองรับการเปลี่ยนแปลงของโปรโตคอลในอนาคตได้อย่างยืดหยุ่น
- การกำหนด รหัสข้อผิดพลาดที่ชัดเจน ช่วยให้การจัดการฝั่ง UI และการดีบักทำได้ง่ายขึ้น
สรุป
Shared Worker
เป็นกลไกหลักสำหรับการแบ่งปันข้อมูลและสถานะข้ามหลายแท็บของเบราว์เซอร์
โครงสร้างที่นำเสนอที่นี่มีการสื่อสาร RPC แบบ type-safe การติดตามความมีชีวิตด้วยฮาร์ทบีต และกลไกการล็อก จึงเป็นดีไซน์ที่แข็งแกร่งซึ่งสามารถนำไปใช้จริงได้ทันที
บนกลไกนี้ คุณยังสามารถนำไปประยุกต์ใช้สร้างแอปพลิเคชันต่อไปนี้ได้
- ทำให้การเข้าถึง IndexedDB เป็นลำดับ (Serializing)
- การรวมและการแชร์การเชื่อมต่อ WebSocket
- การสร้างคิวงานข้ามหลายแท็บ
- การควบคุมอัตรา (throttling) และการส่งการแจ้งเตือนความคืบหน้า
ดังที่เห็น การใช้ประโยชน์จาก Shared Worker
ทำให้สามารถแชร์ข้อมูลและการประมวลผลได้อย่างปลอดภัยและมีประสิทธิภาพข้ามหลายแท็บ
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย