push イベント

ここまでで、ユーザーの登録とプッシュ メッセージの送信について説明しました。次のステップでは、このプッシュ メッセージをユーザーのデバイスで受信し、通知を表示します(その他の必要な処理も行います)。

プッシュ イベント

メッセージが受信されると、Service Worker でプッシュ イベントが送信されます。

プッシュ イベント リスナーを設定するコードは、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.');
    }
});

Service Worker を初めて使用するデベロッパーにとって、このコードで最も奇妙なのは self 変数です。self は、Service Worker である Web Worker でよく使用されます。self は、ウェブページの window のようなグローバル スコープを指します。ただし、Web Worker と Service Worker の場合、self はワーカー自体を参照します。

上の例では、self.addEventListener() は Service Worker 自体にイベント リスナーを追加したものと考えることができます。

プッシュ イベントの例では、データがあるかどうかを確認し、コンソールに出力します。

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() を使用します。

この例では、プッシュイベント リスナーを追加する方法とデータにアクセスする方法を示していますが、2 つの非常に重要な機能が欠落しています。通知が表示されておらず、event.waitUntil() も使用されていません。

待機時間

Service Worker について理解しておくべきことの 1 つは、Service Worker コードの実行タイミングを制御できないことです。ブラウザが、いつウェイクアップするか、いつ終了するかを決定します。「重要な処理で忙しい」とブラウザに伝える唯一の方法は、event.waitUntil() メソッドにプロミスを渡すことです。これにより、渡された Promise が解決されるまで、ブラウザは Service Worker の実行を継続します。

プッシュ イベントの場合、渡された Promise が解決する前に通知を表示する必要があるという追加要件があります。

通知を表示する基本的な例を次に示します。

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

    event.waitUntil(promiseChain);
});

self.registration.showNotification() を呼び出すと、ユーザーに通知が表示されます。このメソッドは、通知が表示されると解決する Promise を返します。

この例をできるだけわかりやすくするために、このプロミスを promiseChain という変数に割り当てました。これは event.waitUntil() に渡されます。冗長なコードであることは承知しておりますが、waitUntil() に渡すべきものを誤解したり、Promise チェーンが破損したりしたことが原因で、さまざまな問題が発生しています。

データのネットワーク リクエストとアナリティクスによるプッシュ イベントのトラッキングを含む、より複雑な例は次のようになります。

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

ここでは、Promise pushReceivedTracking() を返す関数を呼び出しています。この関数は、例として、アナリティクス プロバイダにネットワーク リクエストを送信する関数として扱います。また、ネットワーク リクエストを行い、レスポンスを受け取り、レスポンス データを使用して通知のタイトルとメッセージを表示します。

これらのプロミスを Promise.all() と組み合わせることで、これらのタスクの両方が実行されている間、サービス ワーカーが存続するようにできます。結果の Promise は event.waitUntil() に渡されます。つまり、ブラウザは両方の Promise が完了するまで待機してから、通知が表示されたことを確認し、Service Worker を終了します。

waitUntil() とその使用方法に注意する必要がある理由は、デベロッパーが直面する最も一般的な問題の 1 つとして、Promise チェーンが正しくないか破損している場合に、Chrome にこの「デフォルト」通知が表示されることです。

Chrome のデフォルト通知の画像

Chrome では、プッシュ メッセージが受信され、event.waitUntil() に渡されたプロミスが完了した後に、サービス ワーカーのプッシュ イベントで通知が表示されない場合にのみ、「このサイトはバックグラウンドで更新されました」という通知が表示されます。

デベロッパーがこの問題に直面する主な理由は、コードで self.registration.showNotification() を呼び出すことは多いものの、返された Promise を何もしていないことです。これにより、デフォルトの通知が断続的に表示されます。たとえば、上記の例で 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);
});

見落としがちであることがわかります。

この通知が表示された場合は、Promise チェーンと event.waitUntil() を確認してください。

次のセクションでは、通知のスタイル設定と表示できるコンテンツについて説明します。

次のステップ

Codelab