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();
메시지 전송
메시지는 문자열이거나 구조화된 클론 알고리즘 (문자열, 객체, 배열, Blob, ArrayBuffer, 맵)에서 지원하는 모든 항목일 수 있습니다.
예 - Blob 또는 파일 전송
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 또는 작업자와 통신하기 위해 더 이상 iframe 또는 작업자에 관한 참조를 유지할 필요가 없습니다.
// 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는 동일 출처입니다. 메시지가 동일한 출처에서 오는 것이 보장되므로 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);
};
특정 채널을 '구독'하기만 하면 양방향으로 안전하게 통신할 수 있습니다.
SharedWorkers와의 차이점
여러 창/탭 또는 작업자에게 메시지를 전송해야 하는 간단한 경우에는 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
제가 직접 사용해 보지는 않았으므로 결과가 다를 수 있습니다.