推送事件

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。但對於網路工作站和 Service Worker,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() 方法。這樣一來,瀏覽器會持續執行服務 worker,直到您傳入的承諾已完成為止。

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

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

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(),表示瀏覽器會等待兩個承諾完成,然後檢查是否已顯示通知並終止服務工作者。

我們應該關心 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()

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

後續步驟

程式碼研究室