BroadcastChannel API - 웹용 메시지 버스

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'}));

채널은 자신에게 방송되지 않습니다. 따라서 onmessage 리스너가 있고 동일한 채널의 postMessage()와 같은 페이지에서 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는 동일한 출처입니다. 메시지의 출처가 동일함을 보장하므로 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 APIBroadcastChannel의 주요 차이점은 후자가 메시지를 여러 리스너 (일대다)에 전달하는 수단이라는 것입니다. MessageChannel는 스크립트 간의 직접 일대일 통신을 위한 것입니다. 또한 포트가 양 끝에 있는 채널을 설정해야 하므로 더 복잡합니다.

기능 감지 및 브라우저 지원

현재 Chrome 54, Firefox 38, Opera 41은 Broadcast Channel API를 지원합니다.

if ('BroadcastChannel' in self) {
    // BroadcastChannel API supported!
}

폴리필의 경우 몇 가지가 있습니다.

이러한 기능을 사용해 보지 않았으므로 사용 방법은 다를 수 있습니다.

리소스