Événements push

À ce stade, nous avons abordé l'abonnement d'un utilisateur et l'envoi d'un message push. L'étape suivante consiste à recevoir ce message push sur l'appareil de l'utilisateur et à afficher une notification (ainsi que toute autre tâche que nous pourrions souhaiter effectuer).

Lorsqu'un message est reçu, un événement push est distribué dans votre service worker.

Le code permettant de configurer un écouteur d'événements push doit être assez semblable à tout autre écouteur d'événements que vous écrivez 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 variable self est la partie la plus étrange de ce code pour la plupart des développeurs qui ne connaissent pas encore les service workers. self est couramment utilisé dans les nœuds de calcul Web, qui sont des service workers. self fait référence à la portée globale, un peu comme window dans une page Web. Toutefois, pour les nœuds de calcul Web et les service workers, self fait référence au nœud de calcul lui-même.

Dans l'exemple ci-dessus, self.addEventListener() peut être considéré comme l'ajout d'un écouteur d'événements au service worker lui-même.

Dans l'exemple d'événement push, nous vérifions si des données sont disponibles et imprimons quelque chose dans la console.

Il existe d'autres façons d'analyser les données d'un événement 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 plupart des utilisateurs utilisent json() ou text(), selon ce qu'ils attendent de leur application.

Cet exemple montre comment ajouter un écouteur d'événements push et accéder aux données, mais il manque deux fonctionnalités très importantes. Aucune notification n'est affichée et event.waitUntil() n'est pas utilisé.

Attendre jusqu'à

L'une des choses à savoir sur les service workers est que vous avez peu de contrôle sur le moment où leur code s'exécute. Le navigateur décide à quel moment l'activer et l'arrêter. Le seul moyen de dire au navigateur "Hey, je suis très occupé à faire des choses importantes" est de transmettre une promesse à la méthode event.waitUntil(). Le navigateur maintient ainsi le service worker en cours d'exécution jusqu'à ce que la promesse que vous avez transmise soit résolue.

Avec les événements push, vous devez afficher une notification avant que la promesse que vous avez transmise ne soit résolue.

Voici un exemple de base d'affichage d'une notification :

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

    event.waitUntil(promiseChain);
});

L'appel de self.registration.showNotification() est la méthode qui affiche une notification à l'utilisateur et renvoie une promesse qui sera résolue une fois la notification affichée.

Pour que cet exemple soit aussi clair que possible, j'ai attribué cette promesse à une variable appelée promiseChain. Cette valeur est ensuite transmise à event.waitUntil(). Je sais que ce n'est pas très long, mais j'ai constaté un certain nombre de problèmes qui ont abouti à une mauvaise compréhension de ce qui devait être transmis à waitUntil() ou à la rupture de chaînes de promesses.

Un exemple plus complexe avec une requête réseau pour les données et le suivi de l'événement push avec les données analytiques peut se présenter comme suit :

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

Ici, nous appelons une fonction qui renvoie une promesse pushReceivedTracking(), qui, pour l'exemple, peut faire semblant d'effectuer une requête réseau auprès de notre fournisseur d'analyse. Nous effectuons également une requête réseau, obtenons la réponse et affichons une notification à l'aide des données de réponses pour le titre et le message de la notification.

Nous pouvons nous assurer que le service worker reste actif pendant que ces deux tâches sont effectuées en combinant ces promesses avec Promise.all(). La promesse générée est transmise à event.waitUntil(), ce qui signifie que le navigateur attend que les deux promesses soient terminées avant de vérifier qu'une notification a été affichée et de terminer le service worker.

La raison pour laquelle nous devons nous soucier de waitUntil() et de son utilisation est que l'un des problèmes les plus courants rencontrés par les développeurs est que lorsque la chaîne de promesses est incorrecte ou non fonctionnelle, Chrome affiche la notification "par défaut" suivante:

Image de la notification par défaut dans Chrome

Chrome n'affiche la notification "Ce site a été mis à jour en arrière-plan" que lorsqu'un message push est reçu et que l'événement push dans le service worker n'affiche pas de notification une fois la promesse transmise à event.waitUntil() terminée.

La principale raison pour laquelle les développeurs sont pris au piège est que leur code appelle souvent self.registration.showNotification(), mais qu'ils ne font rien avec la promesse qu'il renvoie. Par conséquent, la notification par défaut s'affiche de manière intermittente. Par exemple, nous pourrions supprimer le retour pour self.registration.showNotification() dans l'exemple ci-dessus et nous risquons de voir cette notification.

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

Vous pouvez voir à quel point il est facile de passer à côté.

N'oubliez pas : si cette notification s'affiche, vérifiez vos chaînes de promesses et event.waitUntil().

Dans la section suivante, nous allons voir ce que nous pouvons faire pour styliser les notifications et les contenus que nous pouvons afficher.

Étapes suivantes

Ateliers de programmation