Eventos push

Até agora, abordamos a inscrição de um usuário e o envio de uma mensagem push. A próxima etapa é receber essa mensagem push no dispositivo do usuário e mostrar uma notificação (assim como qualquer outro trabalho que possamos querer fazer).

O evento push

Quando uma mensagem é recebida, um evento push é enviado no service worker.

O código para configurar um listener de eventos push precisa ser bastante 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 estranha desse código para a maioria dos desenvolvedores que são novos nos service workers é a variável self. self é comumente usado nos Web Workers, que são um service worker. self refere-se ao escopo global, como window em uma página da Web. Mas, para workers da Web e service workers, self se refere ao worker em si.

No exemplo acima, self.addEventListener() pode ser considerado como a adição de um listener de eventos ao próprio service worker.

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

Há outras maneiras de analisar os 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 espera do aplicativo.

Este exemplo demonstra como adicionar um listener de eventos de push e como acessar dados, mas faltam duas funções muito importantes. Ele não mostra uma notificação e não usa event.waitUntil().

Esperar até

Uma das coisas a entender sobre os service workers é que você tem pouco controle sobre quando o código do service worker será executado. O navegador decide quando ativá-lo e quando encerrá-lo. A única maneira de dizer ao navegador: "Ei, estou muito ocupado fazendo coisas importantes" é transmitindo uma promessa para o método event.waitUntil(). Com isso, o navegador vai manter o service worker em execução até que a promessa transmitida seja resolvida.

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

Confira um exemplo básico de exibição de uma notificação:

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

    event.waitUntil(promiseChain);
});

A chamada 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 exibida.

Para manter este exemplo o mais claro possível, atribuí essa promessa a uma variável chamada promiseChain. Depois, ela é transmitida para event.waitUntil(). Sei que isso é muito detalhado, mas já vi vários problemas que culminaram em um mal-entendido sobre o que precisa ser transmitido para waitUntil() ou como resultado de cadeias de promessas quebradas.

Um exemplo mais complicado com uma solicitação de rede para dados e rastreamento do evento push com análise pode ser parecido com este:

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 fará uma solicitação de rede para nosso provedor de análise. Também fazemos uma solicitação de rede, recebemos a resposta e mostramos uma notificação usando os dados de respostas para o título e a mensagem da notificação.

Podemos garantir que o service worker permaneça ativo enquanto ambas as 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.

O motivo pelo qual precisamos nos preocupar com waitUntil() e como usá-lo é que um dos problemas mais comuns que os desenvolvedores enfrentam é que, quando a cadeia de promessas está incorreta ou quebrada, o Chrome mostra esta notificação "padrão":

Uma 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 push no worker do serviço não mostrar uma notificação depois que a promessa transmitida para event.waitUntil() for concluída.

O principal motivo pelo qual os desenvolvedores são pegos é que o código muitas vezes chama self.registration.showNotification(), mas não faz nada com a promessa que ele retorna. Isso faz com que a notificação padrão seja mostrada intermittentemente. Por exemplo, poderíamos remover o retorno de self.registration.showNotification() no exemplo acima e correr o risco de ver esta 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);
});

Dá para ver que é fácil não perceber.

Lembre-se: caso essa notificação seja exibida, verifique suas cadeias de promessas e o event.waitUntil().

Na próxima seção, vamos analisar o que podemos fazer para estilizar notificações e o conteúdo que podemos exibir.

A seguir

Codelabs