Push-события

К этому моменту мы рассмотрели подписку пользователя и отправку push-сообщения. Следующий шаг — получить это push-сообщение на устройстве пользователя и отобразить уведомление (а также выполнить любую другую работу, которую мы можем захотеть выполнить).

Когда сообщение будет получено, в вашем сервис-воркере будет отправлено событие push.

Код для настройки прослушивателя push-событий должен быть очень похож на любой другой прослушиватель событий, который вы пишете на 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.');
    }
});

Самая странная часть этого кода для большинства разработчиков, которые плохо знакомы с сервис-воркерами, — это переменная self . self обычно используется в Web Workers, которыми является сервисный работник. self относится к глобальной области действия, что-то вроде window на веб-странице. Но для веб-работников и сервис-работников self относится к самому работнику.

В приведенном выше примере self.addEventListener() можно рассматривать как добавление прослушивателя событий к самому сервисному работнику.

В примере события push мы проверяем, есть ли какие-либо данные, и выводим что-то на консоль.

Существуют и другие способы анализа данных из события 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()

Большинство людей используют json() или text() в зависимости от того, чего они ожидают от своего приложения.

В этом примере показано, как добавить прослушиватель push-событий и как получить доступ к данным, но в нем отсутствуют две очень важные функции. Он не показывает уведомление и не использует event.waitUntil() .

Подождите, пока

Одна из вещей, которую следует понимать в отношении сервис-воркеров, заключается в том, что у вас мало контроля над тем, когда код сервис-воркера будет запускаться. Браузер решает, когда его активировать, а когда завершить. Единственный способ сказать браузеру: «Эй, я очень занят важными делами» — это передать обещание в метод event.waitUntil() . При этом браузер будет поддерживать работу сервис-воркера до тех пор, пока переданное вами обещание не будет выполнено.

При использовании push-событий существует дополнительное требование: вы должны отобразить уведомление до того, как переданное вами обещание будет выполнено.

Вот базовый пример отображения уведомления:

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

    event.waitUntil(promiseChain);
});

Вызов self.registration.showNotification() — это метод, который отображает уведомление пользователю и возвращает обещание, которое будет выполнено после отображения уведомления.

Чтобы сделать этот пример максимально понятным, я присвоил это обещание переменной с именем promiseChain . Затем это передается в event.waitUntil() . Я знаю, что это очень многословно, но я видел ряд проблем, которые возникли в результате неправильного понимания того, что должно быть передано в waitUntil() , или в результате разрыва цепочки обещаний.

Более сложный пример с сетевым запросом данных и отслеживанием push-события с помощью аналитики может выглядеть так:

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

Здесь мы вызываем функцию, которая возвращает обещание pushReceivedTracking() , которое, ради примера, мы можем представить, что оно отправит сетевой запрос нашему поставщику аналитики. Мы также делаем сетевой запрос, получаем ответ и показываем уведомление, используя данные ответов для заголовка и сообщения уведомления.

Мы можем гарантировать, что сервис-воркер будет оставаться активным, пока выполняются обе эти задачи, объединив эти обещания с Promise.all() . Полученное обещание передается в event.waitUntil() , что означает, что браузер будет ждать завершения обоих обещаний, прежде чем проверять, что уведомление было отображено, и завершать работу сервис-воркера.

Причина, по которой нам следует беспокоиться о waitUntil() и о том, как ее использовать, заключается в том, что одна из наиболее распространенных проблем, с которыми сталкиваются разработчики, заключается в том, что, когда цепочка обещаний неверна или нарушена, Chrome отображает это уведомление «по умолчанию»:

Изображение уведомления по умолчанию в Chrome

Chrome будет отображать только сообщение «Этот сайт был обновлен в фоновом режиме». уведомление, когда получено push-сообщение, а событие push в сервисном работнике не отображает уведомление после завершения обещания, переданного в event.waitUntil() .

Основная причина, по которой разработчики на это попадаются, заключается в том, что их код часто вызывает self.registration.showNotification() , но они ничего не делают с возвращаемым обещанием. Периодически это приводит к отображению уведомления по умолчанию. Например, мы могли бы удалить возврат self.registration.showNotification() в приведенном выше примере, и мы рискуем увидеть это уведомление.

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

Вы видите, как легко это пропустить.

Просто помните: если вы видите это уведомление, проверьте свои цепочки обещаний и event.waitUntil() .

В следующем разделе мы рассмотрим, что мы можем сделать для стилизации уведомлений и какой контент мы можем отображать.

Куда идти дальше

Лаборатории кода