推送事件

Matt Gaunt

此時,我們介紹了訂閱使用者及傳送推送訊息。接下來,您必須在使用者的裝置上接收這則推播訊息,並顯示通知 (以及執行其他可能需要執行的工作)。

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 通常用於網路工作站 (Service Worker)。self 是全域範圍的參照,類似於網頁中的 window。但對網路工作站和服務工作站而言,self 指的是工作站本身。

在上述範例中,self.addEventListener() 可視為在服務工作者本身新增事件監聽器。

在推送事件範例中,我們會檢查是否有任何資料,並將內容輸出至控制台。

您還可以透過其他方式剖析推送事件的資料:

// 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()

這個範例說明如何新增推送事件監聽器以及如何存取資料,但缺少兩項非常重要的功能。未顯示通知,也未使用 event.waitUntil()

Wait Until

關於服務工作站,您必須瞭解的一件事是,您幾乎無法控制服務工作站程式碼的執行時間。瀏覽器會決定何時喚醒及終止該服務。您唯一能向瀏覽器表示「我正忙著處理重要事項」的方法,就是將承諾傳遞至 event.waitUntil() 方法。如此一來,瀏覽器就會維持服務工作處理程序,直到傳入的承諾完成為止。

對於推播事件,您必須在傳入的承諾已完成時才可顯示通知,這是額外規定。

以下是顯示通知的基本範例:

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

    event.waitUntil(promiseChain);
});

呼叫 self.registration.showNotification() 是向使用者顯示通知的方法,並會傳回承諾,在通知顯示後會解析。

為了讓這個範例盡可能清楚,我將這個承諾指派給名為 promiseChain 的變數。然後傳入 event.waitUntil()。我知道這會產生大量文字,但我發現許多問題都是因為誤解應傳入 waitUntil() 的內容,或是因為承諾鏈條中斷而產生。

一個更複雜的範例包含使用網路要求的資料,以及使用分析工具追蹤推送事件的例子,如下所示:

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(),這表示瀏覽器會等到兩項承諾都完成後,再檢查顯示的通知是否已顯示並終止 Service Worker。

我們應該關心 waitUntil() 並瞭解如何使用的原因,是因為開發人員面臨的其中一個最常見問題是,當承諾鏈結不正確/中斷時,Chrome 會顯示這個「預設」通知:

圖片:Chrome 的預設通知

只有在收到推播訊息,且服務工作者中的推播事件在傳遞至 event.waitUntil() 的承諾完成後「不會」顯示通知時,Chrome 才會顯示「This site has been updated in the background」通知。

開發人員遇到這個問題的主因是,他們的程式碼通常會呼叫 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()

在下一節中,我們將探討如何設定通知樣式,以及可顯示的內容。

後續步驟

程式碼研究室