broadcastchannel_api.md (3320B)
1 # Broadcast Channel API 2 3 ``` 4 BroadcastChannel (cross-context bus) 5 --------------------------------------- 6 7 [ Tab 1 ] [ Tab 2 ] [ Worker / Tab 3 ] 8 +-----------+ +-----------+ +-----------------+ 9 | App code | | App code | | App code | 10 | publishes | | subscribes| | subscribes | 11 +-----+-----+ +-----+-----+ +--------+--------+ 12 | | | 13 +---------+---------+-------------------------+ 14 v 15 +-----------------------+ 16 | BroadcastChannel | browser-level bus 17 | ("app-events") | 18 +-----------------------+ 19 ``` 20 21 `BroadcastChannel` is a built-in browser API that lets different browser 22 contexts (tabs, iframes, workers) on the same origin communicate by posting 23 messages to a named channel. It's essentially a pub/sub bus at the browser level 24 — perfect for syncing state across tabs without a server. 25 26 ## Typed BroadcastChannel in TypeScript 27 28 You can wrap it in a typed class to get full compile-time safety: 29 30 ```ts 31 type StateMessage<T> = 32 | { type: "STATE_UPDATE"; payload: Partial<T> } 33 | { type: "REQUEST_SYNC" }; 34 35 class SyncedStore<T extends object> { 36 private state: T; 37 private channel: BroadcastChannel; 38 private subscribers = new Set<(s: T) => void>(); 39 40 constructor(name: string, initial: T) { 41 this.state = { ...initial }; 42 this.channel = new BroadcastChannel(name); 43 this.channel.onmessage = (e: MessageEvent<StateMessage<T>>) => { 44 if (e.data.type === "STATE_UPDATE") { 45 this.state = { ...this.state, ...e.data.payload }; 46 this.subscribers.forEach((cb) => cb(this.state)); 47 } 48 }; 49 } 50 51 setState(updates: Partial<T>) { 52 this.state = { ...this.state, ...updates }; 53 this.channel.postMessage({ type: "STATE_UPDATE", payload: updates }); 54 this.subscribers.forEach((cb) => cb(this.state)); 55 } 56 57 subscribe(cb: (s: T) => void) { 58 this.subscribers.add(cb); 59 return () => this.subscribers.delete(cb); 60 } 61 62 destroy() { 63 this.channel.close(); 64 } 65 } 66 ``` 67 68 TypeScript's MessageEvent<T> generic ensures the e.data payload is typed 69 correctly, preventing you from accidentally posting or reading the wrong shape. 70 71 ### Common Use Cases 72 73 - Session sync — if a user logs out in one tab, broadcast a logout action to 74 immediately reflect that across all open tabs 75 76 - Shopping cart sync — changes made in one tab propagate instantly to others 77 78 - Shared worker state — coordinate state between a ServiceWorker and page tabs 79 80 ### Limitations to Know 81 82 - BroadcastChannel does not fire in the tab that sent the message — only other 83 tabs receive it, so you still update local state directly 84 85 - It only works within the same origin (same protocol + domain + port) 86 87 - It has no built-in message history — a newly opened tab won't get past state 88 unless you implement a REQUEST_SYNC handshake pattern (one tab requests the 89 current state, another responds with it) 90 91 - Not available in IE, but has full support in all modern browsers 92 93 This pattern pairs naturally with the observable store from the previous answer 94 — the BroadcastChannel becomes an external subscriber that mirrors state updates 95 to other tabs.