Signatur
Beschreibung
Die schreibgeschützte Eigenschaft port eines SharedWorker-Objekts liefert einen MessagePort. Anders als bei einem dedizierten Worker hat der Shared Worker selbst keine postMessage()-Methode. Die gesamte Kommunikation läuft über diesen Port.
Ein Shared Worker kann gleichzeitig von mehreren Browsing-Kontexten desselben Ursprungs genutzt werden, also von Tabs, Fenstern oder iframes. Jede Seite, die new SharedWorker(url) aufruft, bekommt einen eigenen Port. Im Worker kommt dieser als event.ports[0] im connect-Ereignis an. So kann der Worker jeden Client einzeln ansprechen oder Nachrichten an alle verbinden Ports verteilen.
Wichtig ist das Starten des Ports: Wer einen Listener über port.onmessage = … setzt, startet den Port automatisch. Wer port.addEventListener("message", …) verwendet, muss port.start() selbst aufrufen. Sonst werden Nachrichten zwar gepuffert, aber nie zugestellt.
Typische Einsatzfälle sind eine gemeinsame WebSocket-Verbindung für alle Tabs, zentrales Zwischenspeichern, das Abgleichen von Zuständen zwischen Tabs (z. B. Login/Logout) oder das Bündeln aufwendiger Berechnungen.
Rückgabewert
postMessage()) und Empfangen (message-Ereignis) von Nachrichten zwischen der Seite und dem Shared Worker. Es ist bei jedem Zugriff dasselbe Objekt.Beispiele
Grundlegende Kommunikation mit onmessage
// main.js
const worker = new SharedWorker('counter-worker.js');
// onmessage startet den Port automatisch
worker.port.onmessage = (event) => {
console.log('Antwort vom Worker:', event.data);
};
worker.port.postMessage({ type: 'increment' });
// counter-worker.js
let count = 0;
onconnect = (event) => {
const port = event.ports[0];
port.onmessage = (e) => {
if (e.data.type === 'increment') {
count += 1;
port.postMessage({ count });
}
};
};
addEventListener mit explizitem start()
const worker = new SharedWorker('worker.js', { name: 'app-sync' });
const { port } = worker;
const handleMessage = (event) => {
console.log('Empfangen:', event.data);
};
port.addEventListener('message', handleMessage);
port.addEventListener('messageerror', (e) => {
console.error('Nachricht nicht deserialisierbar', e);
});
// Ohne start() kommen bei addEventListener keine Nachrichten an!
port.start();
port.postMessage('ping');
Nachricht an alle Tabs verteilen (Broadcast)
// broadcast-worker.js
const ports = new Set();
onconnect = (event) => {
const port = event.ports[0];
ports.add(port);
port.onmessage = ({ data }) => {
if (data.type === 'bye') {
ports.delete(port);
return;
}
// An alle verbundenen Tabs weiterleiten
for (const p of ports) p.postMessage(data);
};
};
// main.js (in jedem Tab)
const worker = new SharedWorker('broadcast-worker.js');
worker.port.onmessage = ({ data }) => {
if (data.type === 'logout') location.href = '/login';
};
window.addEventListener('pagehide', () => {
worker.port.postMessage({ type: 'bye' });
worker.port.close();
});
document.querySelector('#logout')?.addEventListener('click', () => {
worker.port.postMessage({ type: 'logout' });
});
Promise-basierte Anfrage über den Port
const worker = new SharedWorker('api-worker.js');
worker.port.start();
const request = (payload) => new Promise((resolve) => {
const id = crypto.randomUUID();
const onMessage = ({ data }) => {
if (data.id !== id) return;
worker.port.removeEventListener('message', onMessage);
resolve(data.result);
};
worker.port.addEventListener('message', onMessage);
worker.port.postMessage({ id, payload });
});
const result = await request({ action: 'getUser', userId: 42 });
console.log(result);
// Wichtig · Fallstricke
- Port starten: Bei
addEventListener("message", …)mussport.start()aufgerufen werden. Nur die Zuweisung anonmessagestartet den Port automatisch. Das gilt auf beiden Seiten, also auch im Worker. - Kein Ereignis beim Trennen: Schließt ein Tab, erfährt der Worker das nicht zuverlässig. Veraltete Ports sollte man deshalb selbst aufräumen, etwa mit einer „bye“-Nachricht bei
pagehideoder einem Heartbeat. Sonst wächst die Port-Liste immer weiter. - Gleicher Ursprung: Shared Worker werden nur zwischen Kontexten mit gleichem Ursprung, gleicher URL und gleichem
namegeteilt. Partitionierung bei Drittanbietern und private Fenster können eigene Instanzen erzeugen. - Kompatibilität: Chrome für Android und ältere Safari-Versionen vor 16 unterstützen
SharedWorkernicht. Vorher mit'SharedWorker' in windowprüfen und bei Bedarf aufBroadcastChanneloder einen dediziertenWorkerausweichen. - Daten: Nachrichten werden mit dem Structured-Clone-Algorithmus kopiert. Funktionen und DOM-Knoten lassen sich nicht übertragen und lösen einen
DataCloneErroraus. GroßeArrayBuffersollte man als übertragbare Objekte (Transferables) übergeben. - Sicherheit: Eingehende Nachrichten sollten im Worker geprüft werden, denn jeder Tab desselben Ursprungs kann sich verbinden.