Shared Worker ใน JavaScript

Shared Worker ใน JavaScript

บทความนี้อธิบายเกี่ยวกับ Shared Worker ใน JavaScript

เราจะอธิบายทุกอย่างตั้งแต่พื้นฐานของ Shared Worker ไปจนถึงกรณีการใช้งานจริงทีละขั้นตอน

YouTube Video

javascript-shared-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <script>
111        // Override console.log to display messages in the #output element
112        (function () {
113            // Override console.log
114            const originalLog = console.log;
115            console.log = function (...args) {
116                originalLog.apply(console, args);
117                const message = document.createElement('div');
118                message.textContent = args.map(String).join(' ');
119                output.appendChild(message);
120            };
121
122            // Override console.error
123            const originalError = console.error;
124            console.error = function (...args) {
125                originalError.apply(console, args);
126                const message = document.createElement('div');
127                message.textContent = args.map(String).join(' ');
128                message.style.color = 'red'; // Color error messages red
129                output.appendChild(message);
130            };
131        })();
132
133        document.getElementById('executeBtn').addEventListener('click', () => {
134            // Prevent multiple loads
135            if (document.getElementById('externalScript')) return;
136
137            const script = document.createElement('script');
138            script.src = 'javascript-shared-worker.js';
139            script.id = 'externalScript';
140            //script.onload = () => console.log('javascript-shared-worker.js loaded and executed.');
141            //script.onerror = () => console.log('Failed to load javascript-shared-worker.js.');
142            document.body.appendChild(script);
143        });
144    </script>
145</body>
146</html>

Shared Worker ใน JavaScript

Shared Worker คืออะไร?

Shared Worker คือเธรด worker ที่สามารถ ถูกแชร์ระหว่างหลายเพจ (แท็บ, วินโดวส์, iframe ฯลฯ) ภายใน origin เดียวกัน แตกต่างจาก Dedicated Worker ที่ผูกกับหน้าเฉพาะ จุดเด่นหลักคือ กระบวนการแบ็คกราวด์เดียวสามารถใช้งานร่วมกันได้ระหว่างหลายหน้า ตัวอย่างกรณีใช้งานทั่วไป ได้แก่:

  • คุณสามารถ แชร์การเชื่อมต่อ WebSocket เดียวกันระหว่างหลายแท็บ ลดจำนวนการเชื่อมต่อและบริหารจัดการการเชื่อมต่อใหม่จากจุดเดียว
  • คุณสามารถ ซิงโครไนซ์สถานะระหว่างแท็บ (การจัดการแบบศูนย์กลางสำหรับ Pub/Sub หรือสโตร์ต่าง ๆ)
  • คุณสามารถ เรียงลำดับการทำงานของ IndexedDB เพื่อจัดการการเข้าถึงพร้อมกัน
  • คุณสามารถ ป้องกันการทำซ้ำของกระบวนการที่ใช้คำนวณหนัก ๆ

Shared Worker มีบทบาทที่แตกต่างจาก Service Worker Service Worker ส่วนใหญ่ทำหน้าที่เป็นพร็อกซี่เครือข่าย ขณะที่ Shared Worker มุ่งเน้นที่ การคำนวณหรือตัวจัดการสถานะที่ใช้งานร่วมกันระหว่างหลายหน้า

API พื้นฐานและวงจรชีวิต (Lifecycle)

การสร้าง (เธรดหลัก)

 1// main.js
 2// The second argument 'name' serves as an identifier to share the same SharedWorker
 3// if both the URL and name are the same.
 4const worker = new SharedWorker('/shared-worker.js', { name: 'app-core' });
 5
 6// Get the communication port (MessagePort) with this SharedWorker
 7const port = worker.port;
 8
 9// Receive messages with onmessage, send messages with postMessage
10port.onmessage = (ev) => {
11    console.log('From SharedWorker:', JSON.stringify(ev.data));
12};
13
14// When using onmessage, start() is not required
15// (start() is needed when using addEventListener instead)
16port.postMessage({ type: 'hello', from: location.pathname });
  • โค้ดนี้แสดงวิธีการสร้าง Shared Worker และการส่ง/รับข้อความผ่านพอร์ตของมัน

ผู้รับ (ในขอบเขตของ Shared Worker)

 1// shared-worker.js
 2// SharedWorkerGlobalScope has an onconnect event,
 3// and a MessagePort is provided for each connection
 4const ports = new Set();
 5
 6onconnect = (e) => {
 7    const port = e.ports[0];
 8    ports.add(port);
 9
10    port.onmessage = (ev) => {
11        // Log the received message and send a reply back to the sender
12        console.log('From page:', ev.data);
13        port.postMessage({ type: 'ack', received: ev.data });
14    };
15
16    // For handling explicit disconnection from the page (via MessagePort.close())
17    port.onmessageerror = (err) => {
18        console.error('Message error:', err);
19    };
20
21    // Greeting immediately after connection
22    port.postMessage({ type: 'welcome', clientCount: ports.size });
23};
24
25// Explicit termination of the SharedWorker is usually unnecessary
26// (It will be garbage collected when all ports are closed)
  • โค้ดนี้สาธิตการรับ MessagePort ทุกครั้งที่มีการเชื่อมต่อจากแต่ละคลายแอนท์ใน Shared Worker และวิธีประมวลผลและตอบกลับข้อความ

วงจรชีวิตของ Shared Worker

Shared Worker จะเริ่มต้นเมื่อมีการเชื่อมต่อครั้งแรก และอาจ ยุติเมื่อปิดพอร์ตสุดท้าย การเชื่อมต่อจะสิ้นสุดเมื่อรีโหลดหรือปิดหน้า และ worker จะถูกสร้างใหม่หากจำเป็น

Shared Worker คือ "สคริปต์ที่ใช้งานได้นานและใช้ร่วมกันภายในเบราว์เซอร์" หากไม่ระมัดระวังเกี่ยวกับวงจรชีวิตของ Shared Worker อาจเกิดปัญหาเช่น การรั่วไหลของทรัพยากร การคงอยู่ของสถานะเก่า หรือการเริ่มต้นใหม่โดยไม่ตั้งใจได้มากขึ้น

ทดลองใช้: ส่งข้อความระหว่างแท็บ

นี่คือตัวอย่างการใช้งานแบบพื้นฐานที่หลายแท็บเชื่อมต่อกับ Shared Worker เดียวกันและ ทุกข้อความที่ถูกส่งจะถูกกระจายไปยังทุกแท็บ

main.js

 1const worker = new SharedWorker('/shared-worker.js', { name: 'bus' });
 2const port = worker.port;
 3
 4port.onmessage = (ev) => {
 5    const msg = ev.data;
 6    if (msg.type === 'message') {
 7        const li = document.createElement('li');
 8        li.textContent = `[${new Date(msg.at).toLocaleTimeString()}] ${msg.payload}`;
 9        document.querySelector('#messages').appendChild(li);
10    } else if (msg.type === 'ready') {
11        console.log(`Connected. clients=${msg.clients}`);
12    }
13};
14
15document.querySelector('#form').addEventListener('submit', (e) => {
16    e.preventDefault();
17    const input = document.querySelector('#text');
18    port.postMessage({ type: 'publish', payload: input.value });
19    input.value = '';
20});
21
22document.querySelector('#ping').addEventListener('click', () => {
23    port.postMessage({ type: 'ping' });
24});
  • โค้ดนี้เชื่อมต่อกับ Shared Worker พร้อมทั้งแสดงวิธีรับ/แสดงข้อความ ส่งข้อความจากฟอร์ม และส่ง ping เมื่อกดปุ่ม

shared-worker.js

 1// Minimal pub/sub bus in a SharedWorker
 2const subscribers = new Set();
 3
 4/** Broadcast to all connected ports */
 5function broadcast(message) {
 6    for (const port of subscribers) {
 7        try {
 8            port.postMessage(message);
 9        } catch (e) {
10            // Unsubscribe if sending fails, just in case
11            subscribers.delete(port);
12        }
13    }
14}
15
16onconnect = (e) => {
17    const port = e.ports[0];
18    subscribers.add(port);
19
20    port.onmessage = (ev) => {
21        const msg = ev.data;
22        if (msg && msg.type === 'publish') {
23            broadcast({ type: 'message', payload: msg.payload, at: Date.now() });
24        } else if (msg && msg.type === 'ping') {
25            port.postMessage({ type: 'pong', at: Date.now() });
26        }
27    };
28
29    port.postMessage({ type: 'ready', clients: subscribers.size });
30};
  • โค้ดนี้สร้างฟีเจอร์ pub/sub แบบง่ายภายใน Shared Worker เพื่อส่งต่อข้อความระหว่างไคลเอ็นท์หลายตัว

index.html

 1<!doctype html>
 2<html>
 3    <body>
 4        <form id="form">
 5            <input id="text" placeholder="say something" />
 6            <button>Send</button>
 7        </form>
 8        <button id="ping">Ping</button>
 9        <ul id="messages"></ul>
10        <script src="/main.js" type="module"></script>
11    </body>
12</html>
  • เมื่อคุณเปิดเพจนี้ใน หลายแท็บ ข้อความจากแท็บใด ๆ จะถูกแจ้งเตือนให้แท็บอื่นรู้ด้วย

ออกแบบข้อความ: Request/Response และ Correlation ID

เมื่อมีไคลเอ็นท์หลายตัวสื่อสารกับ Shared Worker มักต้องการทราบว่า การตอบกลับใดตรงกับคำขอใด ดังนั้น โดยปกติแล้วจะต้องมีการใส่ correlation ID เพื่อเชื่อมโยงการตอบกลับกับคำขอ

main.js

 1function createClient(workerUrl, name) {
 2    const w = new SharedWorker(workerUrl, { name });
 3    const port = w.port;
 4    const pending = new Map(); // id -> {resolve,reject}
 5    let nextId = 1;
 6
 7    port.onmessage = (ev) => {
 8        const { id, ok, result, error } = ev.data || {};
 9        if (!id || !pending.has(id)) return;
10        const { resolve, reject } = pending.get(id);
11        pending.delete(id);
12        ok ? resolve(result) : reject(new Error(error));
13    };
14
15    function call(method, params) {
16        const id = nextId++;
17        return new Promise((resolve, reject) => {
18            pending.set(id, { resolve, reject });
19            port.postMessage({ id, method, params });
20        });
21    }
22
23    return { call };
24}
25
26// usage
27const client = createClient('/shared-worker.js', 'rpc');
28client.call('add', { a: 2, b: 3 }).then(console.log);   // -> 5
29client.call('sleep', { ms: 500 }).then(console.log);     // -> 'done'
  • โค้ดนี้สร้าง RPC client แบบง่ายที่สามารถเรียกเมทอดแบบอะซิงโครนัสไปยัง Shared Worker ได้ ที่นี่ RPC server (Remote Procedure Call server) หมายถึงเซิร์ฟเวอร์ที่ให้กลไกในการเรียกใช้ฟังก์ชันและกระบวนการจากโปรแกรมหรือโพรเซสอื่น
  • ในตัวอย่างนี้ id จะเพิ่มค่าอย่างง่าย ๆ แต่คุณสามารถใช้ UUID, สตริงสุ่ม หรือรวม timestamp เข้ากับตัวนับเพื่อสร้างคีย์ที่ไม่ซ้ำกันก็ได้

shared-worker.js

 1// A small request/response router with correlation ids
 2onconnect = (e) => {
 3    const port = e.ports[0];
 4
 5    port.onmessage = async (ev) => {
 6        const { id, method, params } = ev.data || {};
 7        try {
 8            let result;
 9            switch (method) {
10                case 'add':
11                    result = (params?.a ?? 0) + (params?.b ?? 0);
12                    break;
13                case 'sleep':
14                    await new Promise(r => setTimeout(r, params?.ms ?? 0));
15                    result = 'done';
16                    break;
17                default:
18                    throw new Error(`Unknown method: ${method}`);
19            }
20            port.postMessage({ id, ok: true, result });
21        } catch (err) {
22            port.postMessage({ id, ok: false, error: String(err) });
23        }
24    };
25};
  • โค้ดนี้เป็นการสร้าง RPC server อย่างง่ายที่ประมวลผลตาม method และส่งผลลัพธ์กลับพร้อมกับ request ID

รูปแบบการใช้งานทั่วไป

มีรูปแบบที่ใช้กันบ่อยกับ Shared Worker ตัวอย่างเช่น:

การแบ่งใช้ WebSocket เดียวกันระหว่างหลายแท็บ (Multiplexing)

หากแต่ละแท็บเปิด WebSocket เอง จะส่งผลกระทบต่อภาระงานของเซิร์ฟเวอร์และข้อจำกัดของจำนวนการเชื่อมต่อ ให้มี WebSocket เพียงหนึ่งเดียว อยู่ใน Shared Worker แล้วแต่ละแท็บส่ง/รับข้อความผ่าน worker นั้น

main.js

 1const w = new SharedWorker('/shared-worker.js', { name: 'ws' });
 2const port = w.port;
 3
 4port.onmessage = (ev) => {
 5    const msg = ev.data;
 6    if (msg.type === 'data') {
 7        console.log('Server says:', msg.payload);
 8    } else if (msg.type === 'socket') {
 9        console.log('WS state:', msg.state);
10    }
11};
12
13function send(payload) {
14    port.postMessage({ type: 'send', payload });
15}
  • โค้ดนี้แสดงการส่ง/รับข้อความกับเซิร์ฟเวอร์ WebSocket และรับการแจ้งเตือนสถานะเชื่อมต่อผ่าน Shared Worker

shared-worker.js

 1let ws;
 2const ports = new Set();
 3
 4function ensureSocket() {
 5    if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
 6        return;
 7    }
 8    ws = new WebSocket('wss://example.com/stream');
 9    ws.onopen = () => broadcast({ type: 'socket', state: 'open' });
10    ws.onclose = () => broadcast({ type: 'socket', state: 'closed' });
11    ws.onerror = (e) => broadcast({ type: 'socket', state: 'error', detail: String(e) });
12    ws.onmessage = (m) => broadcast({ type: 'data', payload: m.data });
13}
14
15function broadcast(msg) {
16    for (const p of ports) p.postMessage(msg);
17}
18
19onconnect = (e) => {
20    const port = e.ports[0];
21    ports.add(port);
22    ensureSocket();
23
24    port.onmessage = (ev) => {
25        const msg = ev.data;
26        if (msg?.type === 'send' && ws?.readyState === WebSocket.OPEN) {
27            ws.send(JSON.stringify(msg.payload));
28        }
29    };
30};
  • โค้ดนี้สร้างกลไกใน Shared Worker เพื่อแชร์การเชื่อมต่อ WebSocket เดียวกัน กระจายสถานะการเชื่อมต่อและข้อมูลที่รับได้ถึง client ทุกตัว ขณะที่ส่งคำขอของแต่ละคลายแอนท์ไปยังเซิร์ฟเวอร์ผ่าน WebSocket เดียวกัน

  • ด้วยการรวมกลยุทธ์การเชื่อมต่อใหม่และการคิวข้อความที่ยังไม่ได้ส่งไว้ใน Shared Worker พฤติกรรมจะสอดคล้องกันในทุกแท็บ

การจัดคิว IndexedDB (Serialization)

เมื่อต้องเข้าถึงฐานข้อมูลเดียวกันจากหลายแท็บ หากต้องการหลีกเลี่ยง ความขัดแย้งจากทรานแซกชันพร้อมกัน หรือการรอล็อค สามารถตั้งคิวใน Shared Worker แล้วประมวลผลทีละรายการ

 1// db-worker.js (very simplified – error handling omitted)
 2let db;
 3async function openDB() {
 4    if (db) return db;
 5    db = await new Promise((resolve, reject) => {
 6        const req = indexedDB.open('appdb', 1);
 7        req.onupgradeneeded = () => req.result.createObjectStore('kv');
 8        req.onsuccess = () => resolve(req.result);
 9        req.onerror = () => reject(req.error);
10    });
11    return db;
12}
13
14async function put(key, value) {
15    const d = await openDB();
16    return new Promise((resolve, reject) => {
17        const tx = d.transaction('kv', 'readwrite');
18        tx.objectStore('kv').put(value, key);
19        tx.oncomplete = () => resolve(true);
20        tx.onerror = () => reject(tx.error);
21    });
22}
23
24async function get(key) {
25    const d = await openDB();
26    return new Promise((resolve, reject) => {
27        const tx = d.transaction('kv', 'readonly');
28        const req = tx.objectStore('kv').get(key);
29        req.onsuccess = () => resolve(req.result);
30        req.onerror = () => reject(req.error);
31    });
32}
33
34onconnect = (e) => {
35    const port = e.ports[0];
36    port.onmessage = async (ev) => {
37        const { id, op, key, value } = ev.data;
38        try {
39            const result = op === 'put' ? await put(key, value) : await get(key);
40            port.postMessage({ id, ok: true, result });
41        } catch (err) {
42            port.postMessage({ id, ok: false, error: String(err) });
43        }
44    };
45};
  • โค้ดนี้สร้างกลไกที่การอ่าน/เขียน IndexedDB ถูกตั้งคิวผ่าน Shared Worker จัดการให้เข้าถึงทีละแท็บและหลีกเลี่ยงปัญหา conflict และ lock

คำแนะนำสำหรับการแยกโมดูลและเครื่องมือ Bundler

ถ้าคุณต้องการเขียนสคริปต์ Shared Worker เป็น ES Module พฤติกรรมและความรองรับจะแตกต่างกันตามแต่ละสภาพแวดล้อม ในการใช้งานจริง แนะนำให้เลือกหนึ่งในสองแนวทางนี้:

  • เขียนแบบ classic worker format และใช้ importScripts() โหลด dependencies เมื่อต้องการ
  • ใช้ฟีเจอร์ worker entry ของ bundler (เช่น Vite / Webpack / esbuild ฯลฯ) และแยก bundle ของ Shared Worker ตอน build

คำแนะนำสำหรับการจัดการข้อผิดพลาด การตรวจจับการตัดการเชื่อมต่อ และความทนทาน

พิจารณาจุดเหล่านี้สำหรับการจัดการข้อผิดพลาดและความทนทาน:

  • การจัดการการส่งข้อความก่อนเชื่อมต่อสำเร็จ ตั้งคิวข้อความที่มาถึงก่อนที่พอร์ตจะพร้อมใช้งาน

  • การตรวจจับการตัดการเชื่อมต่อ MessagePort ไม่มี handler มาตรฐานชื่อ onclose ในฝั่งหลัก ให้ส่งข้อความ {type: 'bye'} ด้วย port.postMessage ระหว่าง beforeunload หรือระบุในโปรโตคอลอย่างชัดเจนเพื่อให้แน่ใจว่า worker ถูกเคลียร์

  • การเชื่อมต่อใหม่ เมื่อรีโหลดหน้าหรือเปิดแท็บใหม่ จะมีพอร์ตใหม่ถูกสร้างขึ้น เตรียม ข้อความซิงโครไนซ์เริ่มต้น (เพื่อส่งสถานะทั้งหมดตั้งแต่ต้น)

  • แรงกดทับข้อมูล (Backpressure) ระหว่างการกระจายข้อความอย่างหนัก ให้เปลี่ยนไปใช้ การหน่วง/ลดความถี่ (throttle/debounce) หรือ ส่ง snapshot แทน

  • ความปลอดภัย Shared Worker ถูกแชร์ภายใน origin เดียวกัน เท่านั้นตามหลักการ หากต้องใส่ข้อมูลลับลงใน worker ให้พิจารณาออกแบบระบบยืนยันตัวตน (เช่น token) สำหรับฝั่งที่เรียกใช้งานด้วย

วิธีการใช้ Dedicated Worker, Shared Worker และ Service Worker อย่างเหมาะสม

Worker แต่ละประเภทมีลักษณะดังนี้:

  • Dedicated Worker Dedicated Worker ถูกออกแบบมาสำหรับใช้กับหน้าเพจเดียวเท่านั้น ช่วยแยกการประมวลผลออกจากส่วน UI แบบ 1:1

  • Shared Worker Shared Worker สามารถถูกใช้งานร่วมกันระหว่างหลายหน้าเพจที่มีต้นทางเดียวกัน เหมาะสำหรับ การสื่อสารระหว่างแท็บ และ การแชร์การเชื่อมต่อเดียวกัน

  • Service Worker Service Worker สามารถใช้งานสำหรับการพร็อกซีเครือข่าย การแคช การทำงานแบบออฟไลน์ การแจ้งเตือนแบบพุช และการซิงค์ข้อมูลเบื้องหลัง จุดเด่นของมันคือความสามารถในการ ดักจับคำขอ fetch

โดยหลักการ: ใช้ Shared Worker สำหรับ 'การแบ่งปันข้อมูลและการประมวลผลระหว่างแท็บ', ใช้ Service Worker สำหรับ 'ควบคุมเครือข่าย', และเลือก Dedicated Worker หากต้องการลดการประมวลผลหนัก ๆ ออกจาก UI

ข้อผิดพลาดที่พบบ่อย

เมื่อใช้ Shared Worker คุณต้องระวังประเด็นดังต่อไปนี้

  • ลืมเรียก start() หรือเรียกโดยไม่จำเป็น เมื่อใช้ port.addEventListener('message', ...) คุณ ต้องเรียก port.start() ไม่จำเป็นต้องเรียกหากใช้ port.onmessage = ...

  • การกระจายข้อมูลแบบไม่จำกัด ภาระงานจะเพิ่มขึ้นตามจำนวนแท็บที่เพิ่มขึ้น สามารถลดภาระงานได้โดยใช้ การส่งแบบกำหนดเป้าหมาย หรือ ระบบหัวข้อสมัครสมาชิก (กรองตามหัวข้อ)

  • ต้นทุนการคัดลอกอ็อบเจกต์ postMessage จะทำการสำเนาข้อมูล สำหรับข้อมูลขนาดใหญ่ ให้พิจารณาส่งแบบ Transferable (เช่น ArrayBuffer) หรือใช้ หน่วยความจำร่วม (SharedArrayBuffer) ร่วมกับ Atomics

  • อายุการใช้งานและการฟื้นคืนสภาพ Shared Worker อาจถูกปิดเมื่อผู้ใช้รายสุดท้ายตัดการเชื่อมต่อ ออกแบบการ initialize สำหรับการเชื่อมต่อครั้งแรกและการเริ่มใหม่ให้เหมาะสม เพื่อลดผลข้างเคียงและบั๊ก

สรุป

  • Shared Worker เป็นสถานที่ที่เหมาะสำหรับการสร้าง ตรรกะแบบกำหนดเองที่แชร์ระหว่างหลายหน้าเป็นเวลานาน
  • ระบุข้อตกลงในการส่งข้อความ (ชนิด/โปรโตคอล) ให้ชัดเจน และออกแบบการร้องขอ/การตอบสนองให้รัดกุมด้วย correlation IDs
  • เหมาะสำหรับกระบวนการที่ควรรวมศูนย์ระหว่างทุกแท็บ เช่น การมัลติเพล็กซ์การเชื่อมต่อ WebSocket หรือ การควบคุมการเข้าถึง IndexedDB แบบเรียงลำดับ
  • การปรับแต่งรายละเอียด เช่น bundler, การกำหนดชนิดข้อมูล และการเชื่อมต่อใหม่ สามารถ เพิ่มความง่ายในการดูแลและประสบการณ์ผู้ใช้งานอย่างมาก

คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย

YouTube Video