경우에 따라 웹 앱은 페이지와 서비스 워커 간에 양방향 통신 채널을 설정해야 할 수 있습니다.
예를 들어 팟캐스트 PWA에서 사용자가 오프라인 소비를 위해 에피소드를 다운로드할 수 있는 기능을 빌드하고 서비스 워커가 페이지에 진행 상황을 정기적으로 알리도록 허용하여 기본 스레드가 UI를 업데이트할 수 있습니다.
이 가이드에서는 다양한 API, Workbox 라이브러리, 몇 가지 고급 사례를 살펴보고 창과 서비스 워커 컨텍스트 간의 양방향 통신을 구현하는 다양한 방법을 살펴봅니다.

Workbox 사용
workbox-window
은 창 컨텍스트에서 실행되도록 설계된 Workbox 라이브러리의 모듈 집합입니다. Workbox
클래스는 인스턴스의 등록된 서비스 워커에 메시지를 보내고 응답을 기다리는 messageSW()
메서드를 제공합니다.
다음 페이지 코드는 새 Workbox
인스턴스를 만들고 서비스 워커에 메시지를 전송하여 버전을 가져옵니다.
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
서비스 워커는 다른 쪽에서 메시지 리스너를 구현하고 등록된 서비스 워커에 응답합니다.
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
내부적으로 이 라이브러리는 다음 섹션에서 검토할 브라우저 API인 Message Channel을 사용하지만 많은 구현 세부정보를 추상화하여 사용하기 쉬우며 이 API가 제공하는 광범위한 브라우저 지원을 활용합니다.

브라우저 API 사용
Workbox 라이브러리가 필요에 충분하지 않은 경우 페이지와 서비스 워커 간에 양방향 통신을 구현하는 데 사용할 수 있는 여러 하위 수준 API가 있습니다. 다음과 같은 유사점과 차이점이 있습니다.
유사점:
- 모든 경우에 통신은
postMessage()
인터페이스를 통해 한쪽 끝에서 시작되고message
핸들러를 구현하여 다른 쪽 끝에서 수신됩니다. - 실제로 사용 가능한 모든 API를 사용하면 동일한 사용 사례를 구현할 수 있지만 일부 API는 특정 시나리오에서 개발을 간소화할 수 있습니다.
차이점:
- 통신의 다른 쪽을 식별하는 방법은 다양합니다. 다른 컨텍스트에 대한 명시적 참조를 사용하는 방법도 있고 각 측면에서 인스턴스화된 프록시 객체를 통해 암시적으로 통신하는 방법도 있습니다.
- 브라우저 지원은 각각 다릅니다.

Broadcast Channel API
브로드캐스트 채널 API를 사용하면 BroadcastChannel 객체를 통해 탐색 컨텍스트 간에 기본적인 통신이 가능합니다.
이를 구현하려면 먼저 각 컨텍스트가 동일한 ID로 BroadcastChannel
객체를 인스턴스화하고 메시지를 보내고 받아야 합니다.
const broadcast = new BroadcastChannel('channel-123');
BroadcastChannel 객체는 수신 대기 중인 컨텍스트에 메시지를 전송하는 postMessage()
인터페이스를 노출합니다.
//send message
broadcast.postMessage({ type: 'MSG_ID', });
모든 브라우저 컨텍스트는 BroadcastChannel
객체의 onmessage
메서드를 통해 메시지를 수신 대기할 수 있습니다.
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
보시다시피 특정 컨텍스트에 대한 명시적 참조가 없으므로 서비스 워커나 특정 클라이언트에 대한 참조를 먼저 가져올 필요가 없습니다.

단점은 이 문서를 작성하는 시점에 API가 Chrome, Firefox, Edge에서 지원되지만 Safari와 같은 다른 브라우저에서는 아직 지원하지 않는다는 것입니다.
Client API
클라이언트 API를 사용하면 서비스 워커가 제어하는 활성 탭을 나타내는 모든 WindowClient
객체에 대한 참조를 가져올 수 있습니다.
페이지가 단일 서비스 워커에 의해 제어되므로 serviceWorker
인터페이스를 통해 활성 서비스 워커에 직접 메시지를 수신하고 전송합니다.
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
마찬가지로 서비스 워커는 onmessage
리스너를 구현하여 메시지를 수신 대기합니다.
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
클라이언트와 다시 통신하기 위해 서비스 워커는 Clients.matchAll()
및 Clients.get()
과 같은 메서드를 실행하여 WindowClient
객체의 배열을 가져옵니다. 그런 다음 다음 중 하나를 postMessage()
할 수 있습니다.
//Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
if (clients && clients.length) {
//Respond to last focused tab
clients[0].postMessage({type: 'MSG_ID'});
}
});

Client API
는 비교적 간단한 방법으로 서비스 워커에서 활성 탭과 쉽게 통신할 수 있는 좋은 옵션입니다. 이 API는 모든 주요 브라우저에서 지원되지만 일부 메서드는 사용하지 못할 수 있으므로 사이트에 구현하기 전에 브라우저 지원을 확인하세요.
메시지 채널
메시지 채널을 사용하려면 양방향 통신 채널을 설정하기 위해 한 컨텍스트에서 다른 컨텍스트로 포트를 정의하고 전달해야 합니다.
채널을 초기화하기 위해 페이지는 MessageChannel
객체를 인스턴스화하고 이를 사용하여 등록된 서비스 워커에 포트를 전송합니다. 페이지는 다른 컨텍스트에서 메시지를 수신하기 위해 onmessage
리스너도 구현합니다.
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};

서비스 워커는 포트를 수신하고, 포트에 대한 참조를 저장하고, 이를 사용하여 다른 쪽에 메시지를 전송합니다.
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
MessageChannel
는 현재 모든 주요 브라우저에서 지원됩니다.
고급 API: 백그라운드 동기화 및 백그라운드 가져오기
이 가이드에서는 실행할 작업을 설명하는 문자열 메시지나 캐시할 URL 목록을 한 컨텍스트에서 다른 컨텍스트로 전달하는 것과 같이 비교적 간단한 사례에 대해 양방향 통신 기법을 구현하는 방법을 살펴봤습니다. 이 섹션에서는 연결 부족 및 긴 다운로드라는 두 가지 특정 시나리오를 처리하는 두 가지 API를 살펴봅니다.
백그라운드 동기화
채팅 앱은 연결 불량으로 인해 메시지가 손실되지 않도록 해야 할 수 있습니다. 백그라운드 동기화 API를 사용하면 사용자의 연결이 안정적일 때 다시 시도할 작업을 지연할 수 있습니다. 이는 사용자가 보내려는 내용이 실제로 전송되도록 하는 데 유용합니다.
postMessage()
인터페이스 대신 페이지는 sync
를 등록합니다.
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
그러면 서비스 워커가 sync
이벤트를 수신 대기하여 메시지를 처리합니다.
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
doSomeStuff()
함수는 시도하는 작업의 성공/실패를 나타내는 프로미스를 반환해야 합니다. 프로미스가 이행되면 동기화가 완료됩니다. 실패하면 다시 시도하도록 다른 동기화가 예약됩니다. 동기화 재시도도 연결을 기다리고 지수 백오프를 사용합니다.
작업이 실행되면 서비스 워커는 앞에서 살펴본 통신 API 중 하나를 사용하여 페이지와 다시 통신하여 UI를 업데이트할 수 있습니다.
Google 검색은 백그라운드 동기화를 사용하여 연결 불량으로 인해 실패한 쿼리를 유지하고 사용자가 온라인 상태일 때 나중에 다시 시도합니다. 작업이 실행되면 웹 푸시 알림을 통해 사용자에게 결과를 전달합니다.

백그라운드 가져오기
메일 전송이나 캐시할 URL 목록과 같이 비교적 짧은 작업의 경우 지금까지 살펴본 옵션이 적합합니다. 작업이 너무 오래 걸리면 브라우저에서 서비스 워커를 종료합니다. 그렇지 않으면 사용자의 개인 정보 보호 및 배터리에 위험이 됩니다.
백그라운드 가져오기 API를 사용하면 영화, 팟캐스트 또는 게임 레벨 다운로드와 같은 긴 작업을 서비스 워커로 오프로드할 수 있습니다.
페이지에서 서비스 워커와 통신하려면 postMessage()
대신 backgroundFetch.fetch
를 사용하세요.
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch(
'my-fetch',
['/ep-5.mp3', 'ep-5-artwork.jpg'],
{
title: 'Episode 5: Interesting things.',
icons: [
{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
},
],
downloadTotal: 60 * 1024 * 1024,
},
);
});
BackgroundFetchRegistration
객체를 사용하면 페이지에서 progress
이벤트를 수신 대기하여 다운로드 진행률을 추적할 수 있습니다.
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(
(bgFetch.downloaded / bgFetch.downloadTotal) * 100,
);
console.log(`Download progress: ${percent}%`);
});

다음 단계
이 가이드에서는 페이지와 서비스 워커 간의 가장 일반적인 통신 사례(양방향 통신)를 살펴봤습니다.
응답을 받지 않고 다른 컨텍스트와 통신하는 데 하나의 컨텍스트만 필요한 경우가 많습니다. 서비스 워커에서 페이지로, 페이지에서 서비스 워커로 단방향 기술을 구현하는 방법과 사용 사례, 프로덕션 예시는 다음 가이드를 참고하세요.
- 명령형 캐싱 가이드: 페이지에서 서비스 워커를 호출하여 리소스를 미리 캐시합니다 (예: 프리패치 시나리오).
- 업데이트 브로드캐스트: 서비스 워커에서 페이지를 호출하여 중요한 업데이트 (예: 새로운 버전의 웹 앱이 제공됨)에 관해 알립니다.