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 debería ser bastante similar a cualquier otro objeto de escucha de eventos que escribas 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 Web Workers, que es un trabajador de servicio. self hace referencia al alcance global, similar a window en una página web. Sin embargo, para los trabajadores web y los trabajadores de servicio, self hace referencia al propio trabajador.

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 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 he visto 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":

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 trabajador de servicio no muestre una notificación después de que finalice 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 hace que se muestre de forma intermitente 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

Code labs