Beberapa situs mungkin perlu berkomunikasi dengan pekerja layanan tanpa perlu diberi tahu tentang hasilnya. Berikut beberapa contohnya:
- Halaman mengirimkan daftar URL kepada pekerja layanan untuk di-prefetch, sehingga, saat pengguna mengklik link, sub-resource dokumen atau halaman sudah tersedia di cache, sehingga navigasi berikutnya jauh lebih cepat.
- Halaman meminta pekerja layanan untuk mengambil dan meng-cache sekumpulan artikel teratas, agar artikel tersebut tersedia untuk tujuan offline.
Mendelegasikan jenis tugas non-penting ini ke pekerja layanan memiliki manfaat untuk mengosongkan thread utama agar dapat menangani tugas yang lebih mendesak dengan lebih baik, seperti merespons interaksi pengguna.
Dalam panduan ini, kita akan mempelajari cara menerapkan teknik komunikasi satu arah dari halaman ke pekerja layanan menggunakan API browser standar dan library Workbox. Kita menyebut jenis kasus penggunaan ini sebagai cache imperatif.
Kasus produksi
1-800-Flowers.com menerapkan caching imperatif (pra-pengambilan) dengan pekerja layanan melalui
postMessage()
untuk melakukan pra-pengambilan
item teratas di halaman kategori guna mempercepat navigasi berikutnya ke halaman detail produk.
Dia menggunakan pendekatan campuran untuk memutuskan item mana yang akan diambil sebelumnya:
- Pada waktu pemuatan halaman, mereka meminta pekerja layanan untuk mengambil data JSON untuk 9 item teratas, dan menambahkan objek respons yang dihasilkan ke cache.
- Untuk item yang tersisa, item tersebut memproses peristiwa
mouseover
, sehingga, saat pengguna memindahkan kursor ke atas item, mereka dapat memicu pengambilan resource secara "on demand".
API ini menggunakan Cache API untuk menyimpan respons JSON:
Saat pengguna mengklik item, data JSON yang terkait dengannya dapat diambil dari cache, tanpa perlu membuka jaringan, sehingga navigasi menjadi lebih cepat.
Menggunakan Workbox
Workbox menyediakan cara mudah untuk mengirim pesan ke
pekerja layanan, melalui paket workbox-window
, yaitu kumpulan modul
yang dimaksudkan untuk berjalan dalam konteks jendela. Paket ini merupakan pelengkap untuk paket Workbox lainnya
yang berjalan di pekerja layanan.
Untuk berkomunikasi dengan halaman menggunakan pekerja layanan, pertama-tama dapatkan referensi objek Workbox ke pekerja layanan yang terdaftar:
const wb = new Workbox('/sw.js');
wb.register();
Kemudian, Anda dapat langsung mengirim pesan secara deklaratif, tanpa perlu repot mendapatkan pendaftaran, memeriksa aktivasi, atau memikirkan API komunikasi yang mendasarinya:
wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });
Pekerja layanan menerapkan pengendali message
untuk memproses pesan ini. Secara opsional, metode ini dapat menampilkan respons, meskipun dalam kasus seperti ini, hal ini
tidak diperlukan:
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PREFETCH') {
// do something
}
});
Menggunakan API browser
Jika library Workbox tidak cukup untuk kebutuhan Anda, berikut cara menerapkan komunikasi pekerja jendela ke layanan, menggunakan API browser.
postMessage API dapat digunakan untuk membuat mekanisme komunikasi satu arah dari halaman ke pekerja layanan.
Halaman memanggil
postMessage()
di
antarmuka pekerja layanan:
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
payload: 'some data to perform the task',
});
Pekerja layanan menerapkan pengendali message
untuk
memproses pesan ini.
self.addEventListener('message', (event) => {
if (event.data && event.data.type === MSG_ID) {
// do something
}
});
Atribut {type : 'MSG_ID'}
tidak mutlak diperlukan, tetapi ini adalah salah satu cara untuk mengizinkan halaman
mengirim berbagai jenis petunjuk ke pekerja layanan (yaitu, 'untuk melakukan pengambilan data sebelumnya' vs. 'untuk menghapus
penyimpanan'). Pekerja layanan dapat bercabang ke berbagai jalur eksekusi berdasarkan flag ini.
Jika operasi berhasil, pengguna akan dapat memperoleh manfaat darinya, tetapi jika tidak, operasi tersebut tidak akan mengubah alur penggunaan utama. Misalnya, saat 1-800-Flowers.com mencoba melakukan pra-cache, halaman tidak perlu mengetahui apakah pekerja layanan berhasil atau tidak. Jika demikian, pengguna akan menikmati navigasi yang lebih cepat. Jika tidak, halaman masih harus membuka halaman baru. Hanya perlu sedikit lebih lama.
Contoh pengambilan data sederhana
Salah satu aplikasi caching imperatif yang paling umum adalah prefetching, yang berarti mengambil resource untuk URL tertentu, sebelum pengguna beralih ke URL tersebut, untuk mempercepat navigasi.
Ada berbagai cara untuk menerapkan pengambilan data di situs:
- Menggunakan Tag pengambilan data link di halaman: resource disimpan di cache browser selama lima menit, setelah itu aturan
Cache-Control
normal untuk resource akan diterapkan. - Melengkapi teknik sebelumnya dengan strategi caching runtime di pekerja layanan untuk memperpanjang masa pakai resource pengambilan data di luar batas ini.
Untuk skenario pengambilan data yang relatif sederhana, seperti pengambilan data dokumen, atau aset tertentu (JS, CSS, dll.), teknik tersebut adalah pendekatan terbaik.
Jika logika tambahan diperlukan, misalnya, mengurai resource pengambilan data (file atau halaman JSON) untuk mengambil URL internalnya, sebaiknya delegasikan tugas ini sepenuhnya ke pekerja layanan.
Mendelegasikan jenis operasi ini ke pekerja layanan memiliki keuntungan berikut:
- Memindahkan beban pemrosesan pengambilan dan pasca-pengambilan (yang akan diperkenalkan nanti) ke thread sekunder. Dengan melakukan hal ini, thread utama akan bebas untuk menangani tugas yang lebih penting seperti merespons interaksi pengguna.
- Mengizinkan beberapa klien (misalnya tab) untuk menggunakan kembali fungsi umum, dan bahkan memanggil layanan secara bersamaan tanpa memblokir thread utama.
Mengambil halaman detail produk terlebih dahulu
Pertama, gunakan postMessage()
di
antarmuka pekerja layanan dan teruskan array URL untuk di-cache:
navigator.serviceWorker.controller.postMessage({
type: 'PREFETCH',
payload: {
urls: [
'www.exmaple.com/apis/data_1.json',
'www.exmaple.com/apis/data_2.json',
],
},
});
Di pekerja layanan, terapkan pengendali message
untuk
mencegat dan memproses pesan yang dikirim oleh tab aktif:
addEventListener('message', (event) => {
let data = event.data;
if (data && data.type === 'PREFETCH') {
let urls = data.payload.urls;
for (let i in urls) {
fetchAsync(urls[i]);
}
}
});
Pada kode sebelumnya, kita memperkenalkan fungsi bantuan kecil yang disebut fetchAsync()
untuk melakukan iterasi pada
array URL dan mengeluarkan permintaan pengambilan untuk setiap URL:
async function fetchAsync(url) {
// await response of fetch call
let prefetched = await fetch(url);
// (optionally) cache resources in the service worker storage
}
Saat respons diperoleh, Anda dapat mengandalkan header caching resource. Namun, dalam banyak kasus, seperti di halaman detail produk, resource tidak di-cache (yang berarti, resource memiliki header Cache-control
dari no-cache
). Dalam kasus seperti ini, Anda dapat mengganti perilaku ini, dengan menyimpan resource yang diambil di cache pekerja layanan. Hal ini memiliki manfaat tambahan untuk memungkinkan
file ditayangkan dalam skenario offline.
Di luar data JSON
Setelah data JSON diambil dari endpoint server, data ini sering kali berisi URL lain yang juga layak untuk pengambilan data, seperti gambar atau data endpoint lainnya yang dikaitkan dengan data tingkat pertama ini.
Misalnya, dalam contoh ini, data JSON yang ditampilkan adalah informasi situs belanja bahan makanan:
{
"productName": "banana",
"productPic": "https://cdn.example.com/product_images/banana.jpeg",
"unitPrice": "1.99"
}
Ubah kode fetchAsync()
untuk melakukan iterasi pada daftar produk dan menyimpan gambar hero ke dalam cache untuk
setiap produk:
async function fetchAsync(url, postProcess) {
// await response of fetch call
let prefetched = await fetch(url);
//(optionally) cache resource in the service worker cache
// carry out the post fetch process if supplied
if (postProcess) {
await postProcess(prefetched);
}
}
async function postProcess(prefetched) {
let productJson = await prefetched.json();
if (productJson && productJson.product_pic) {
fetchAsync(productJson.product_pic);
}
}
Anda dapat menambahkan beberapa penanganan pengecualian di sekitar kode ini untuk situasi seperti 404. Namun, keunggulan penggunaan pekerja layanan untuk melakukan pengambilan data sebelumnya adalah dapat gagal tanpa banyak akibat pada halaman dan thread utama. Anda juga dapat memiliki logika yang lebih rumit dalam pasca-pemrosesan konten yang diambil datanya, sehingga lebih fleksibel dan terpisah dengan data yang ditanganinya. Tak ada yang membatasimu.
Kesimpulan
Dalam artikel ini, kami membahas kasus penggunaan umum komunikasi satu arah antara pekerja halaman dan layanan: caching imperatif. Contoh yang dibahas hanya dimaksudkan untuk menunjukkan salah satu cara menggunakan pola ini dan pendekatan yang sama juga dapat diterapkan ke kasus penggunaan lainnya, misalnya, meng-cache artikel teratas sesuai permintaan untuk konsumsi offline, bookmark, dan lainnya.
Untuk pola komunikasi halaman dan pekerja layanan lainnya, lihat:
- Menyebarkan update: Memanggil halaman dari pekerja layanan untuk menginformasikan update penting (misalnya, versi baru webapp tersedia).
- Komunikasi dua arah: Mendelegasikan tugas ke pekerja layanan (misalnya download berat), dan memberi tahu halaman tentang progresnya.