BroadcastChannel API를 사용하면 동일한 출처 스크립트가 다른 탐색 컨텍스트로 메시지를 보낼 수 있습니다. 이는 창/탭, iframe, 웹 워커 및 서비스 워커 간에 Pub/Sub 시맨틱을 허용하는 간단한 메시지 버스로 생각할 수 있습니다.
API 기본사항
Broadcast Channel API는 탐색 컨텍스트 간에 더 쉽게 통신하도록 하는 간단한 API입니다. 즉, 창/탭, iframe, 웹 워커 및 서비스 워커 간에 통신합니다. 특정 채널에 게시되는 메시지는 해당 채널의 모든 청취자에게 전달됩니다.
BroadcastChannel
생성자는 단일 매개변수, 즉 채널 이름을 사용합니다.
이름은 채널을 식별하고 탐색 컨텍스트 전반에 걸쳐 사용됩니다.
// Connect to the channel named "my_bus".
const channel = new BroadcastChannel('my_bus');
// Send a message on "my_bus".
channel.postMessage('This is a test message.');
// Listen for messages on "my_bus".
channel.onmessage = function(e) {
console.log('Received', e.data);
};
// Close the channel when you're done.
channel.close();
메시지 전송
메시지는 문자열이거나 구조화된 클론 알고리즘 (String, Objects, Arrays, Blobs, ArrayBuffer, Map)에서 지원하는 문자열일 수 있습니다.
예 - Blob 또는 File 전송
channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));
자신에게는 채널이 방송되지 않습니다. 따라서 동일한 채널의 postMessage()
와 동일한 페이지에 onmessage
리스너가 있으면 message
이벤트가 실행되지 않습니다.
다른 기법과의 차이점
이 시점에서 이 방법이 WebSockets, SharedWorkers, MessageChannel
API, window.postMessage()
과 같은 다른 메시지 전달 기법과 어떤 관련이 있는지 궁금할 수 있습니다. Broadcast Channel API는 이러한 API를 대체하지 않습니다. 각각은 특정한 목적을 수행합니다. Broadcast Channel API는 동일한 출처에 있는 스크립트 간의 쉬운 일대다 통신을 위한 것입니다.
방송 채널의 사용 사례:
- 다른 탭에서 사용자 작업 감지
- 사용자가 다른 창/탭에서 계정에 로그인하면 알림
- 작업자에게 백그라운드 작업을 실행하도록 안내
- 서비스가 어떤 작업을 실행했을 때 이를 알 수 있습니다.
- 사용자가 하나의 창에서 사진을 업로드하면 열려 있는 다른 페이지로 옮깁니다.
예: 사용자가 언제 로그아웃하는지 알 수 있는 페이지: 동일한 사이트에 있는 다른 탭에서도 로그아웃하는 경우
<button id="logout">Logout</button>
<script>
function doLogout() {
// update the UI login state for this page.
}
const authChannel = new BroadcastChannel('auth');
const button = document.querySelector('#logout');
button.addEventListener('click', e => {
// A channel won't broadcast to itself so we invoke doLogout()
// manually on this page.
doLogout();
authChannel.postMessage({cmd: 'logout', user: 'Eric Bidelman'});
});
authChannel.onmessage = function(e) {
if (e.data.cmd === 'logout') {
doLogout();
}
};
</script>
다른 예를 들어 사용자가 앱에서 '오프라인 저장소 설정'을 변경한 후 캐시된 콘텐츠를 삭제하도록 서비스 워커에 지시한다고 가정해 보겠습니다. window.caches
를 사용하여 캐시를 삭제할 수 있지만, 서비스 워커에 이미 이 작업을 수행하는 유틸리티가 포함되어 있을 수 있습니다. Broadcast Channel API를 사용하여 이 코드를 재사용할 수 있습니다. Broadcast Channel API가 없으면 서비스 워커에서 모든 클라이언트와 통신하기 위해 self.clients.matchAll()
의 결과를 반복하고 각 클라이언트에서 postMessage()
를 호출해야 합니다 (이러한 작업을 실행하는 실제 코드). 방송 채널을 사용하면 O(N)
가 아닌 O(1)
가 됩니다.
예 - 내부 유틸리티 메서드를 재사용하여 캐시를 삭제하도록 서비스 워커에 지시합니다.
index.html
const channel = new BroadcastChannel('app-channel');
channel.onmessage = function(e) {
if (e.data.action === 'clearcache') {
console.log('Cache removed:', e.data.removed);
}
};
const messageChannel = new MessageChannel();
// Send the service worker a message to clear the cache.
// We can't use a BroadcastChannel for this because the
// service worker may need to be woken up. MessageChannels do that.
navigator.serviceWorker.controller.postMessage({
action: 'clearcache',
cacheName: 'v1-cache'
}, [messageChannel.port2]);
sw.js
function nukeCache(cacheName) {
return caches.delete(cacheName).then(removed => {
// ...do more stuff (internal) to this service worker...
return removed;
});
}
self.onmessage = function(e) {
const action = e.data.action;
const cacheName = e.data.cacheName;
if (action === 'clearcache') {
nukeCache(cacheName).then(removed => {
// Send the main page a response via the BroadcastChannel API.
// We could also use e.ports[0].postMessage(), but the benefit
// of responding with the BroadcastChannel API is that other
// subscribers may be listening.
const channel = new BroadcastChannel('app-channel');
channel.postMessage({action, removed});
});
}
};
postMessage()
과의 차이
postMessage()
와 달리 더 이상 iframe 또는 worker와 통신하기 위해 iframe 또는 worker와 통신하기 위해 참조를 유지하지 않아도 됩니다.
// Don't have to save references to window objects.
const popup = window.open('https://another-origin.com', ...);
popup.postMessage('Sup popup!', 'https://another-origin.com');
window.postMessage()
를 사용하면 출처 간에 통신할 수도 있습니다. Broadcast Channel API는 same-origin입니다. 메시지는 동일한 출처에서 온 것이 보장되므로 다음과 같이 window.postMessage()
를 사용할 때처럼 확인할 필요가 없습니다.
// Don't have to validate the origin of a message.
const iframe = document.querySelector('iframe');
iframe.contentWindow.onmessage = function(e) {
if (e.origin !== 'https://expected-origin.com') {
return;
}
e.source.postMessage('Ack!', e.origin);
};
특정 채널을 간단히 '구독'하여 안전한 양방향 커뮤니케이션을 할 수 있습니다.
SharedWorker와의 차이점
BroadcastChannel
는 잠재적으로 여러 창/탭 또는 작업자에게 메시지를 보내야 하는 간단한 사례에 사용합니다.
잠금 관리, 공유 상태, 서버와 여러 클라이언트 간 리소스 동기화, 원격 호스트와 WebSocket 연결을 공유하는 것과 같은 고급 사용 사례의 경우 공유 작업자가 가장 적합한 솔루션입니다.
MessageChannel API와의 차이점
Channel Messaging API와 BroadcastChannel
의 주요 차이점은 후자가 여러 리스너 (일대다)에 메시지를 전달하는 수단이라는 점입니다. MessageChannel
는 스크립트 간에 직접 일대일 통신을 위한 것입니다. 또한 더 복잡하므로 양쪽 끝에 포트를 사용하여 채널을 설정해야 합니다.
기능 감지 및 브라우저 지원
현재 Chrome 54, Firefox 38, Opera 41은 Broadcast Channel API를 지원합니다.
if ('BroadcastChannel' in self) {
// BroadcastChannel API supported!
}
폴리필의 경우 다음과 같은 몇 가지 방법이 있습니다.
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
시도해 본 적이 없어서 주행 거리가 다를 수 있습니다.