Eventos push

Até aqui, abordamos a inscrição de um usuário e o envio de uma mensagem push. A próxima etapa é receber essa mensagem de push no dispositivo do usuário e exibir uma notificação, assim como realizar qualquer outro trabalho que queiramos fazer.

O evento Push

Quando uma mensagem é recebida, ela resulta no envio de um evento push no service worker.

O código para configurar um listener de eventos push é bem semelhante a qualquer outro listener de eventos que você escreveria em 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.');
    }
});

A parte mais esquisita desse código para a maioria dos desenvolvedores iniciantes nos service workers é a variável self. self é comumente usado em Web Workers, o que é um service worker. self refere-se ao escopo global, mais ou menos como window em uma página da Web. No entanto, para workers da Web e service workers, self refere-se ao próprio worker.

No exemplo acima, considere que self.addEventListener() adiciona um listener de eventos ao próprio service worker.

No exemplo do evento de push, verificamos se há dados e imprimimos algo no console.

Há outras maneiras de analisar dados de um evento push:

// 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()

A maioria das pessoas usa json() ou text(), dependendo do que esperar do aplicativo.

Este exemplo demonstra como adicionar um listener de eventos push e como acessar dados, mas não inclui duas funcionalidades muito importantes. Uma notificação não é mostrada nem faz uso de event.waitUntil().

Esperar até

Uma das coisas que você precisa entender sobre service workers é que você tem pouco controle sobre quando o código deles será executado. O navegador decide quando ativar e encerrar. A única maneira de dizer ao navegador que eu estou muito ocupado fazendo coisas importantes é transmitir uma promessa para o método event.waitUntil(). Com isso, o navegador manterá o service worker em execução até que a promessa que você transmitiu seja resolvida.

Com eventos push, há um requisito extra de que você precisa exibir uma notificação antes que a promessa transmitida seja resolvida.

Este é um exemplo básico de como mostrar uma notificação:

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

    event.waitUntil(promiseChain);
});

Chamar self.registration.showNotification() é o método que mostra uma notificação para o usuário e retorna uma promessa que será resolvida quando a notificação for mostrada.

Para manter esse exemplo o mais claro possível, atribuí essa promessa a uma variável chamada promiseChain. Em seguida, ele é transmitido para event.waitUntil(). Sei que isso é muito detalhado, mas vi vários problemas que culminaram como resultado de um entendimento equivocado sobre o que precisa ser transmitido para waitUntil() ou como resultado de cadeias de promessa inrompidas.

Um exemplo mais complicado com uma solicitação de rede para dados e o rastreamento do evento de push com análise pode ter esta aparência:

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

Aqui, estamos chamando uma função que retorna uma promessa pushReceivedTracking() que, para fins de exemplo, podemos fingir que vamos fazer uma solicitação de rede para nosso provedor de análise. Também estamos fazendo uma solicitação de rede, recebendo a resposta e mostrando uma notificação usando os dados de resposta para o título e a mensagem da notificação.

Podemos garantir que o service worker continue ativo enquanto as duas tarefas são feitas combinando essas promessas com Promise.all(). A promessa resultante é transmitida para event.waitUntil(), o que significa que o navegador aguardará até que as duas promessas sejam concluídas antes de verificar se uma notificação foi exibida e encerrar o service worker.

Precisamos nos preocupar com waitUntil() e como usá-lo porque um dos problemas mais comuns que os desenvolvedores enfrentam é que, quando a cadeia de promessas está incorreta / corrompida, o Chrome mostra esta notificação "padrão":

Imagem da notificação padrão no Chrome

O Chrome só vai mostrar a notificação "Este site foi atualizado em segundo plano" quando uma mensagem push for recebida e o evento de push no service worker não mostrar uma notificação após a conclusão da promessa transmitida para event.waitUntil().

O principal motivo pelo qual os desenvolvedores são capturados por isso é que o código costuma chamar self.registration.showNotification(), mas eles não estão fazendo nada com a promessa retornada. Isso resulta de maneira intermitente na notificação padrão. Por exemplo, podemos remover o retorno de self.registration.showNotification() no exemplo acima e corremos o risco de receber essa notificação.

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

Você pode perceber como é fácil não notar.

Lembre-se: se você receber essa notificação, verifique suas cadeias de promessas e event.waitUntil().

Na próxima seção, vamos descobrir o que podemos fazer para definir o estilo das notificações e qual conteúdo podemos exibir.

A seguir

Laboratórios de códigos