Eventos push

Hasta este punto, explicamos cómo suscribir a un usuario y enviar un mensaje push. El siguiente paso es recibir este mensaje push en el dispositivo del usuario y mostrar una notificación (además de realizar cualquier otra tarea que deseemos).

El evento push

Cuando se reciba un mensaje, se enviará un evento push en tu service worker.

El código para configurar un objeto de escucha de eventos push debe ser bastante similar al de cualquier otro objeto de escucha de eventos que escribirías en 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.');
    }
});

La parte más extraña de este código para la mayoría de los desarrolladores que no están familiarizados con los service workers es la variable self. self se usa comúnmente en los trabajadores web, que es un service worker. self hace referencia al alcance global, como window en una página web. Sin embargo, para los trabajadores web y service workers, self se refiere al trabajador en sí.

En el ejemplo anterior, se puede considerar que self.addEventListener() agrega un objeto de escucha de eventos al mismo servicio de trabajo.

Dentro del ejemplo de evento push, verificamos si hay datos y, luego, imprimimos algo en la consola.

Existen otras formas de analizar datos a partir de un 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()

La mayoría de las personas usan json() o text() según lo que esperan de su aplicación.

En este ejemplo, se muestra cómo agregar un objeto de escucha de eventos push y cómo acceder a los datos, pero le faltan dos funciones muy importantes. No muestra una notificación ni usa event.waitUntil().

Esperar hasta

Una de las cosas que debes comprender sobre los trabajadores de servicio es que tienes poco control sobre cuándo se ejecutará el código del trabajador de servicio. El navegador decide cuándo activarlo y cuándo finalizarlo. La única forma de decirle al navegador "Hey, estoy muy ocupado haciendo tareas importantes" es pasar una promesa al método event.waitUntil(). Con esto, el navegador mantendrá el service worker en ejecución hasta que se resuelva la promesa que pasaste.

Con los eventos push, existe un requisito adicional que consiste en que debes mostrar una notificación antes de que se resuelva la promesa que pasaste.

Este es un ejemplo básico de cómo mostrar una notificación:

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

    event.waitUntil(promiseChain);
});

Llamar a self.registration.showNotification() es el método que muestra una notificación al usuario y muestra una promesa que se resolverá una vez que se muestre la notificación.

Para que este ejemplo sea lo más claro posible, asigné esta promesa a una variable llamada promiseChain. Luego, se pasa a event.waitUntil(). Sé que esto es muy detallado, pero vi varios problemas que se debieron a malentendidos sobre lo que se debe pasar a waitUntil() o a cadenas de promesas rotas.

Un ejemplo más complicado con una solicitud de red para obtener datos y hacer un seguimiento del evento push con la analítica podría verse de la siguiente manera:

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

Aquí llamamos a una función que muestra una promesa pushReceivedTracking(), que, a modo de ejemplo, podemos fingir que realizará una solicitud de red a nuestro proveedor de estadísticas. También realizamos una solicitud de red, obtenemos la respuesta y mostramos una notificación con los datos de las respuestas para el título y el mensaje de la notificación.

Podemos asegurarnos de que el trabajador de servicio se mantenga activo mientras se realizan ambas tareas combinando estas promesas con Promise.all(). La promesa resultante se pasa a event.waitUntil(), lo que significa que el navegador esperará hasta que finalicen ambas promesas antes de verificar que se haya mostrado una notificación y finalizar el servicio trabajador.

El motivo por el que debemos preocuparnos por waitUntil() y cómo usarlo es que uno de los problemas más comunes que enfrentan los desarrolladores es que, cuando la cadena de promesas es incorrecta o está dañada, Chrome muestra esta notificación "predeterminada":

Una imagen de la notificación predeterminada en Chrome

Chrome solo mostrará la notificación "Este sitio se actualizó en segundo plano" cuando se reciba un mensaje push y el evento push en el service worker no muestre ninguna notificación después de que haya finalizado la promesa que se pasó a event.waitUntil().

El motivo principal por el que los desarrolladores se ven afectados por esto es que, a menudo, su código llama a self.registration.showNotification(), pero no hace nada con la promesa que muestra. Esto genera de forma intermitente que se muestre la notificación predeterminada. Por ejemplo, podríamos quitar la devolución de self.registration.showNotification() en el ejemplo anterior y corremos el riesgo de ver esta notificación.

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

Puedes ver que es fácil pasarlo por alto.

Recuerda que, si ves esa notificación, debes revisar tus cadenas de promesas y event.waitUntil().

En la siguiente sección, veremos qué podemos hacer para aplicar diseño a las notificaciones y qué contenido podemos mostrar.

Próximos pasos

Codelabs