Sự kiện đẩy

Đến đây, chúng ta đã đề cập đến việc đăng ký cho người dùng và gửi thông báo đẩy. Bước tiếp theo là nhận thông báo đẩy này trên thiết bị của người dùng và hiển thị một thông báo (cũng như thực hiện mọi công việc khác mà chúng ta có thể muốn thực hiện).

Sự kiện đẩy

Khi nhận được tin nhắn, sự kiện đẩy sẽ được gửi đi trong trình chạy dịch vụ.

Mã để thiết lập trình nghe sự kiện đẩy phải khá giống với mọi trình nghe sự kiện khác mà bạn đã viết trong 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.');
    }
});

Điều kỳ lạ nhất của mã này đối với hầu hết các nhà phát triển mới làm quen với trình thực thi dịch vụ là biến self. self thường được sử dụng trong Web Workers, tức là trình chạy dịch vụ. self là phạm vi toàn cục, tương tự như window trong một trang web. Tuy nhiên, đối với trình thực thi web và trình chạy dịch vụ, self đề cập đến chính trình thực thi đó.

Trong ví dụ trên, bạn có thể coi self.addEventListener() là cách thêm trình nghe sự kiện vào chính trình chạy dịch vụ.

Trong ví dụ về sự kiện đẩy, chúng ta sẽ kiểm tra xem có dữ liệu nào không và in nội dung nào đó lên bảng điều khiển.

Có nhiều cách khác để bạn có thể phân tích cú pháp dữ liệu từ một sự kiện đẩy:

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

Hầu hết mọi người sử dụng json() hoặc text() tuỳ thuộc vào điều họ mong đợi từ ứng dụng của họ.

Ví dụ này minh hoạ cách thêm trình nghe sự kiện đẩy và cách truy cập dữ liệu, nhưng trình nghe này thiếu 2 chức năng rất quan trọng. Cửa sổ này không hiển thị thông báo và không sử dụng event.waitUntil().

Chờ đến

Một trong những điều cần hiểu về trình chạy dịch vụ là bạn có ít quyền kiểm soát đối với thời điểm chạy mã trình chạy dịch vụ. Trình duyệt quyết định thời điểm đánh thức trình duyệt cũng như thời điểm kết thúc. Cách duy nhất bạn có thể nói với trình duyệt: "Ok, tôi đang quá bận làm những việc quan trọng", là truyền một lời hứa vào phương thức event.waitUntil(). Với phương thức này, trình duyệt sẽ tiếp tục duy trì trình chạy dịch vụ cho đến khi lời hứa mà bạn đã truyền vào được xử lý xong.

Với các sự kiện đẩy, có thêm một yêu cầu là bạn phải hiển thị thông báo trước khi lời hứa mà bạn đã truyền vào đã được giải quyết.

Dưới đây là ví dụ cơ bản về cách hiển thị một thông báo:

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

    event.waitUntil(promiseChain);
});

Việc gọi self.registration.showNotification() là phương thức hiển thị thông báo cho người dùng và phương thức này sẽ trả về một lời hứa sẽ giải quyết sau khi thông báo được hiển thị.

Để ví dụ này rõ ràng nhất có thể, tôi đã gán lời hứa này cho một biến tên là promiseChain. Sau đó, hàm này được truyền vào event.waitUntil(). Tôi biết vấn đề này rất chi tiết, nhưng tôi đã gặp một số vấn đề lên đến đỉnh là do hiểu sai nội dung nào nên được truyền vào waitUntil() hoặc do chuỗi hứa hẹn bị hỏng.

Sau đây là một ví dụ phức tạp hơn về yêu cầu mạng cho dữ liệu và theo dõi sự kiện đẩy bằng dữ liệu phân tích:

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

Ở đây, chúng ta sẽ gọi một hàm trả về một lời hứa pushReceivedTracking(). Ví dụ: chúng ta có thể giả vờ rằng sẽ gửi một yêu cầu mạng đến nhà cung cấp phân tích của chúng ta. Chúng tôi cũng sẽ tạo một yêu cầu mạng, nhận phản hồi và hiển thị một thông báo sử dụng dữ liệu phản hồi cho tiêu đề và nội dung của thông báo đó.

Chúng ta có thể đảm bảo trình chạy dịch vụ duy trì hoạt động trong khi cả hai tác vụ này được thực hiện bằng cách kết hợp các lời hứa này với Promise.all(). Lời hứa cuối cùng được chuyển vào event.waitUntil(), tức là trình duyệt sẽ đợi cho đến khi cả hai lời hứa kết thúc trước khi kiểm tra để đảm bảo rằng một thông báo đã được hiển thị và chấm dứt trình chạy dịch vụ.

Lý do chúng ta nên quan tâm đến waitUntil() và cách sử dụng nó là một trong những vấn đề phổ biến nhất mà nhà phát triển gặp phải là khi chuỗi lời hứa không chính xác / bị hỏng, Chrome sẽ hiển thị thông báo "mặc định" này:

Hình ảnh thông báo mặc định trong Chrome

Chrome sẽ chỉ hiển thị thông báo "This site have been updated in the background" (Trang web này đã được cập nhật ở chế độ nền). Khi nhận được thông báo đẩy và sự kiện đẩy trong trình chạy dịch vụ sẽ không hiển thị thông báo sau khi lời hứa được chuyển đến event.waitUntil() kết thúc.

Nguyên nhân chính khiến các nhà phát triển gặp phải vấn đề này là mã của họ thường gọi self.registration.showNotification() nhưng họ không thực hiện bất cứ điều gì với hứa hẹn sẽ được trả về. Việc này không liên tục dẫn đến việc thông báo mặc định sẽ xuất hiện. Ví dụ: chúng ta có thể xoá dữ liệu trả về của self.registration.showNotification() trong ví dụ trên và có nguy cơ nhìn thấy thông báo này.

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

Bạn có thể thấy đây là một kênh dễ bỏ lỡ.

Hãy nhớ rằng – nếu bạn thấy thông báo đó, hãy kiểm tra chuỗi lời hứa và event.waitUntil().

Trong phần tiếp theo, chúng ta sẽ xem những việc chúng ta có thể làm để tạo kiểu cho thông báo và nội dung chúng ta có thể hiển thị.

Điểm đến tiếp theo

Lớp học lập trình