푸시 이벤트

이제까지 사용자를 구독하고 푸시 메시지를 전송하는 방법을 알아봤습니다. 다음 단계는 사용자의 기기에서 이 푸시 메시지를 수신하고 알림을 표시하는 것입니다 (그리고 원하는 다른 작업을 실행하는 것).

메시지가 수신되면 서비스 워커에서 푸시 이벤트가 전달됩니다.

푸시 이벤트 리스너를 설정하는 코드는 JavaScript로 작성하는 다른 이벤트 리스너와 매우 유사합니다.

self.addEventListener('push', function(event) {
   
if (event.data) {
    console
.log('This push event has data: ', event.data.text());
   
} else {
    console
.log('This push event has no data.');
   
}
});

서비스 워커를 처음 접하는 대부분의 개발자에게 이 코드에서 가장 이상한 부분은 self 변수입니다. self는 서비스 워커인 웹 작업자에서 일반적으로 사용됩니다. self는 웹페이지의 window와 마찬가지로 전역 범위를 나타냅니다. 하지만 웹 워커와 서비스 워커의 경우 self는 작업자 자체를 참조합니다.

위 예에서 self.addEventListener()는 서비스 워커 자체에 이벤트 리스너를 추가하는 것으로 생각할 수 있습니다.

푸시 이벤트 예시 내에서 데이터가 있는지 확인하고 콘솔에 출력합니다.

푸시 이벤트에서 데이터를 파싱하는 다른 방법도 있습니다.

// Returns string
event
.data.text()

// Parses data as JSON string and returns an Object
event
.data.json()

// Returns blob of data
event
.data.blob()

// Returns an arrayBuffer
event
.data.arrayBuffer()

대부분의 사람들은 애플리케이션에서 기대하는 바에 따라 json() 또는 text()를 사용합니다.

이 예에서는 푸시 이벤트 리스너를 추가하고 데이터에 액세스하는 방법을 보여줍니다. 하지만 매우 중요한 두 가지 기능이 누락되어 있습니다. 알림이 표시되지 않고 event.waitUntil()를 사용하지 않습니다.

대기 시간

서비스 워커에 관해 알아야 할 사항 중 하나는 서비스 워커 코드가 실행되는 시점을 거의 제어할 수 없다는 것입니다. 브라우저가 언제 기기를 깨울지, 언제 종료할지 결정합니다. 브라우저에 '중요한 일을 하느라 너무 바쁩니다'라고 알리는 유일한 방법은 event.waitUntil() 메서드에 약속을 전달하는 것입니다. 이렇게 하면 브라우저는 전달된 프라미스가 확인될 때까지 서비스 워커를 실행 상태로 유지합니다.

푸시 이벤트의 경우 전달한 약속이 처리되기 전에 알림을 표시해야 한다는 추가 요구사항이 있습니다.

다음은 알림을 표시하는 기본 예입니다.

self.addEventListener('push', function(event) {
   
const promiseChain = self.registration.showNotification('Hello, World.');

    event
.waitUntil(promiseChain);
});

self.registration.showNotification()를 호출하면 사용자에게 알림이 표시되고 알림이 표시된 후 해결되는 약속이 반환됩니다.

이 예시를 최대한 명확하게 유지하기 위해 이 약속을 promiseChain라는 변수에 할당했습니다. 그런 다음 event.waitUntil()에 전달됩니다. 매우 장황하지만 waitUntil()에 전달해야 하는 항목을 오해하거나 약속 체인이 손상되어 발생한 여러 문제가 있었습니다.

데이터에 대한 네트워크 요청과 분석으로 푸시 이벤트를 추적하는 더 복잡한 예는 다음과 같습니다.

self.addEventListener('push', function(event) {
   
const analyticsPromise = pushReceivedTracking();
   
const pushInfoPromise = fetch('/api/get-more-data')
   
.then(function(response) {
       
return response.json();
   
})
   
.then(function(response) {
       
const title = response.data.userName + ' says...';
       
const message = response.data.message;

       
return self.registration.showNotification(title, {
        body
: message
       
});
   
});

   
const promiseChain = Promise.all([
    analyticsPromise
,
    pushInfoPromise
   
]);

    event
.waitUntil(promiseChain);
});

여기서는 Promise pushReceivedTracking()를 반환하는 함수를 호출합니다. 이 함수는 예를 들어 분석 제공업체에 네트워크를 요청하는 것으로 가정할 수 있습니다. 또한 네트워크 요청을 하고 응답을 가져와 응답 데이터를 사용하여 알림의 제목과 메시지로 알림을 표시합니다.

이러한 약속을 Promise.all()와 결합하여 두 작업이 모두 실행되는 동안 서비스 워커가 활성 상태로 유지되도록 할 수 있습니다. 결과 프라미스는 event.waitUntil()에 전달됩니다. 즉, 브라우저는 두 프라미스가 모두 완료될 때까지 기다린 후 알림이 표시되었는지 확인하고 서비스 워커를 종료합니다.

waitUntil() 및 사용 방법에 관해 우려해야 하는 이유는 개발자가 직면하는 가장 일반적인 문제 중 하나가 약속 체인이 잘못되거나 손상되면 Chrome에 다음과 같은 '기본' 알림이 표시된다는 점 때문입니다.

Chrome의 기본 알림 이미지

Chrome은 푸시 메시지가 수신되고 event.waitUntil()에 전달된 약속이 완료된 후 서비스 워커의 푸시 이벤트가 알림을 표시하지 않는 경우에만 '이 사이트가 백그라운드에서 업데이트되었습니다.' 알림을 표시합니다.

개발자가 이 문제에 걸리는 주된 이유는 코드가 self.registration.showNotification()를 자주 호출하지만 반환되는 약속으로 아무것도 하지 않기 때문입니다. 이로 인해 간헐적으로 기본 알림이 표시됩니다. 예를 들어 위의 예에서 self.registration.showNotification()의 반환을 삭제하면 이 알림이 표시될 수 있습니다.

self.addEventListener('push', function(event) {
   
const analyticsPromise = pushReceivedTracking();
   
const pushInfoPromise = fetch('/api/get-more-data')
   
.then(function(response) {
       
return response.json();
   
})
   
.then(function(response) {
       
const title = response.data.userName + ' says...';
       
const message = response.data.message;

        self
.registration.showNotification(title, {
        body
: message
       
});
   
});

   
const promiseChain = Promise.all([
    analyticsPromise
,
    pushInfoPromise
   
]);

    event
.waitUntil(promiseChain);
});

놓치기 쉬운 부분임을 알 수 있습니다.

이 알림이 표시되면 약속 체인과 event.waitUntil()를 확인하세요.

다음 섹션에서는 알림의 스타일을 지정하는 방법과 표시할 수 있는 콘텐츠를 살펴봅니다.

다음에 수행할 작업

Codelab