서비스 워커와의 양방향 통신

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

웹 앱이 양방향 통신 채널을 서비스 워커의 일종입니다.

예: 팟캐스트 PWA에서는 사용자가 에피소드를 다운로드할 수 있는 기능을 구축할 수 있습니다. 오프라인 소비와 정기적으로 페이지에 진행 상황을 알려주므로 기본 스레드는 UI를 업데이트할 수 있습니다.

이 가이드에서는 Google 네트워크 간 양방향 통신을 구현하는 다양한 방법을 Window서비스 근로자 컨텍스트를 사용하여 다양한 API, Workbox 라이브러리, 사용할 수 있습니다.

<ph type="x-smartling-placeholder">
</ph> 서비스 워커와 메시지를 교환하는 페이지를 보여주는 다이어그램

Workbox 사용

workbox-windowWorkbox 라이브러리의 모듈을 사용하여 창 컨텍스트에서 실행할 수 있습니다 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를 사용하며 이 API는 다음 섹션에서 살펴보겠습니다. Message 채널로 분류되지만 와이드 브라우저를 활용하면서 보다 쉽게 사용할 수 있도록 구현 세부정보에 관한 지원을 받을 수 있습니다.

Workbox 창을 사용하여 페이지와 서비스 워커 간의 양방향 통신을 보여주는 다이어그램입니다.

브라우저 API 사용

Workbox 라이브러리가 요구 사항을 충족하는 데 충분하지 않다면 몇 가지 하위 수준 API를 사용하여 페이지와 서비스 워커 간의 '양방향' 통신을 구현합니다. 몇 가지 유사점이 있습니다. 차이점:

유사점:

  • 모든 경우 통신은 postMessage() 인터페이스를 통해 한쪽 끝에서 시작되고 수신됩니다. 다른 쪽 끝에는 message 핸들러를 구현합니다.
  • 실제로 사용 가능한 모든 API를 사용하면 동일한 사용 사례를 구현할 수 있지만 그중 일부는 개발을 간소화할 수 있습니다

차이점:

  • 그들은 커뮤니케이션의 반대쪽을 식별하는 다양한 방법이 있습니다. 일부는 다른 컨텍스트에 대한 명시적 참조, 다른 컨텍스트는 프록시를 통해 암시적으로 통신할 수 있음 각 측에서 인스턴스화됩니다.
  • 브라우저 지원 여부는 서비스마다 다릅니다.
페이지와 서비스 워커 간의 양방향 통신과 사용 가능한 브라우저 API를 보여주는 다이어그램입니다.

방송 채널 API

브라우저 지원

  • Chrome: 54.
  • Edge: 79.
  • Firefox: 38.
  • Safari 15.4.

소스

Broadcast Channel API BroadcastChannel을 통한 탐색 컨텍스트 간의 기본 통신을 허용함 객체를 사용하여 빌드됩니다.

이를 구현하려면 먼저 각 컨텍스트가 동일한 ID로 BroadcastChannel 객체를 인스턴스화해야 합니다. 거기에서 메시지를 보내고 받습니다.

const broadcast = new BroadcastChannel('channel-123');

BroadcastChannel 객체는 postMessage() 인터페이스를 노출하여 수신 대기하는 모든 채널에 메시지를 전송합니다. 컨텍스트:

//send message
broadcast.postMessage({ type: 'MSG_ID', });

모든 브라우저 컨텍스트는 BroadcastChannelonmessage 메서드를 통해 메시지를 리슨할 수 있습니다. 객체:

//listen to messages
broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //process message...
  }
};

보시다시피 특정 컨텍스트에 대한 명시적 참조는 없으므로 서비스 워커나 특정 클라이언트를 먼저 참조합니다.

브로드캐스트 채널 객체를 사용하여 페이지와 서비스 워커 간의 양방향 통신을 보여주는 다이어그램

단점은 이 문서를 작성하는 시점에서 API가 Chrome, Firefox Safari와 같은 다른 브라우저에서는 지원되지 않습니다. 아직이 없습니다.

Client API

브라우저 지원

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1.

소스

클라이언트 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
  }
});

클라이언트와 다시 통신하기 위해 서비스 워커는 다음을 실행하여 WindowClient 객체를 만듭니다. 다음과 같은 방법을 사용합니다. Clients.matchAll()Clients.get(): 그러면 다음 중 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는 모든 주요 API 또는 브라우저, 일부 메서드를 사용할 수 없으므로, 시작하기 전에 브라우저 지원을 사이트에 구현해 보세요.

메시지 채널

브라우저 지원

  • Chrome: 2.
  • Edge: 12.
  • Firefox: 41.
  • Safari: 5.

소스

메시지 채널 요구사항 양방향 통신을 위해 한 컨텍스트에서 다른 컨텍스트로 포트를 정의하고 전달하여 채널을 구독합니다.

페이지에서는 채널을 초기화하기 위해 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를 살펴보겠습니다. 시나리오: 연결 부족 및 긴 다운로드

백그라운드 동기화

브라우저 지원

  • Chrome: 49
  • Edge: 79.
  • Firefox: 지원되지 않음
  • Safari: 지원되지 않음

소스

채팅 앱에서 연결 불량으로 인해 메시지가 손실되는 일이 없도록 할 수 있습니다. 이 Background Sync 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() 함수는 성공/실패를 나타내는 프로미스를 반환해야 합니다. 하고 있습니다. 조건을 충족하면 동기화가 완료된 것입니다. 실패하면 다음 작업에 대한 또 다른 동기화가 예약됩니다. 다시 시도합니다. 동기화 재시도 역시 연결을 대기하며 지수 백오프를 사용합니다.

작업이 완료되면 서비스 워커는 페이지와 다시 통신하여 UI를 업데이트할 수 있습니다

Google 검색은 백그라운드 동기화를 사용하여 연결 불량으로 인해 실패한 쿼리를 유지하고 다시 시도합니다. 나중에 사용자가 온라인 상태가 되면 데이터를 전송할 수 있습니다 작업이 완료되면 결과를 웹 푸시 알림을 통해 사용자에게 알립니다.

<ph type="x-smartling-placeholder">
</ph> 양방향 통신을 설정하기 위해 포트를 서비스 워커에 전달하는 페이지를 보여주는 다이어그램입니다.

배경 가져오기

브라우저 지원

  • Chrome: 74
  • Edge: 79.
  • Firefox: 지원되지 않음
  • Safari: 지원되지 않음

소스

메시지 또는 캐시할 URL 목록 전송과 같이 비교적 짧은 작업의 경우 선택하는 것이 좋습니다 작업이 너무 오래 걸리면 브라우저가 서비스를 중단합니다. 그렇지 않으면 사용자의 개인 정보 보호 및 배터리에 위험을 초래할 수 있습니다.

Background Fetch API 영화, 팟캐스트, 레벨을 다운로드하는 등 긴 작업을 서비스 워커에게 맡길 수 있습니다. 만들 수 있습니다.

페이지에서 서비스 워커와 통신하려면backgroundFetch.fetch postMessage():

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}%`);
});
<ph type="x-smartling-placeholder">양방향 통신을 설정하기 위해 포트를 서비스 워커에 전달하는 페이지를 보여주는 다이어그램입니다.</ph>
UI가 업데이트되어 다운로드 진행 상황이 표시됩니다 (왼쪽). 서비스 워커 덕분에 모든 탭이 닫혀도 (오른쪽) 작업을 계속 실행할 수 있습니다.

다음 단계

이 가이드에서는 페이지와 서비스 워커 간의 가장 일반적인 커뮤니케이션 사례를 살펴보았습니다. (양방향 통신)에서 작동합니다

많은 경우, 한 사용자는 메시지를 받지 않고도 다른 하나와 통신하는 데 하나의 컨텍스트만 필요할 수 있습니다. 있습니다. 단방향 기법을 구현하는 방법은 다음 가이드를 사용 사례 및 프로덕션 예제와 함께 서비스 워커와 페이지를 주고받는 방법에 대해 설명합니다.

  • 명령적 캐싱 가이드: 페이지에서 서비스 워커를 호출하여 사전에 캐시 리소스를 캐시합니다 (예: 미리 가져오기 시나리오).
  • 브로드캐스트 업데이트: 서비스 워커에서 페이지를 호출하여 (예: 새로운 버전의 웹 앱을 사용할 수 있는 경우))을 알릴 수 있습니다.