Beberapa situs mungkin perlu berkomunikasi dengan pekerja layanan tanpa perlu mengetahui hasilnya. Berikut beberapa contohnya:
- Halaman mengirim pekerja layanan daftar URL untuk mengambil data sehingga, saat pengguna mengklik link, dokumen atau subresource halaman sudah tersedia di cache, sehingga navigasi selanjutnya jauh lebih cepat.
- Halaman akan meminta pekerja layanan untuk mengambil dan meng-cache kumpulan artikel teratas agar tersedia untuk tujuan offline.
Pendelegasian jenis tugas non-kritis ini ke pekerja layanan akan berguna, yaitu mengosongkan thread utama, untuk menangani tugas yang lebih mendesak dengan lebih baik, seperti merespons interaksi pengguna.
![Diagram halaman yang meminta resource untuk meng-cache ke service worker.](https://web.dev/static/articles/imperative-caching-guide/image/diagram-a-page-requestin-f19107d4e4aec.png?authuser=6&hl=id)
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 akan menyebut jenis kasus penggunaan ini sebagai cache imperatif.
Kasus produksi
1-800-Flowers.com menerapkan cache imperatif (pengambilan data) dengan pekerja layanan melalui
postMessage()
untuk mengambil data
item teratas di halaman kategori guna mempercepat navigasi berikutnya ke halaman detail produk.
![Logo 1-800 Flowers.](https://web.dev/static/articles/imperative-caching-guide/image/logo-1-800-flowers-94f008b879df2.png?authuser=6&hl=id)
Mereka menggunakan pendekatan campuran untuk memutuskan item mana yang akan diambil data:
- 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 akan memproses peristiwa
mouseover
, sehingga saat pengguna memindahkan kursor ke atas item, mereka dapat memicu pengambilan resource saat "permintaan".
Contoh tersebut menggunakan Cache API untuk menyimpan respons JSON:
![Logo 1-800 Flowers.](https://web.dev/static/articles/imperative-caching-guide/image/logo-1-800-flowers-ee1b000c680c6.png?authuser=6&hl=id)
Ketika pengguna mengklik item, data JSON yang terkait dengan item tersebut dapat diambil dari cache, tanpa perlu masuk ke jaringan, sehingga navigasi menjadi lebih cepat.
Menggunakan Workbox
Workbox menyediakan cara mudah untuk mengirim pesan ke
pekerja layanan, melalui paket workbox-window
, sekumpulan modul
yang dimaksudkan untuk dijalankan dalam konteks jendela. Library ini adalah pelengkap paket Workbox lainnya
yang berjalan di pekerja layanan.
Untuk mengomunikasikan halaman dengan 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 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. API ini dapat menampilkan respons secara opsional, 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 jendela ke pekerja layanan, menggunakan API browser.
postMessage API dapat digunakan untuk membuat mekanisme komunikasi satu arah dari halaman ke pekerja layanan.
Halaman memanggil
postMessage()
pada
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 mengambil data' vs. 'menghapus penyimpanan'). Pekerja layanan dapat bercabang ke dalam jalur eksekusi yang berbeda berdasarkan flag ini.
Jika operasi berhasil, pengguna akan bisa mendapatkan manfaatnya tetapi, jika tidak, itu tidak akan mengubah alur pengguna utama. Misalnya, saat 1-800-Flowers.com mencoba melakukan precache, halaman tidak perlu mengetahui apakah pekerja layanan berhasil. Jika ya, maka pengguna akan menikmati navigasi yang lebih cepat. Jika tidak, halaman masih harus membuka halaman baru. Hanya butuh waktu sedikit lebih lama.
Contoh pengambilan data sederhana
Salah satu penerapan yang paling umum dari cache imperatif adalah pengambilan data, yang berarti mengambil resource untuk URL tertentu, sebelum pengguna berpindah ke URL tersebut, untuk mempercepat navigasi.
Ada berbagai cara untuk menerapkan pengambilan data di situs:
- Menggunakan tag pengambilan 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 melebihi 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 (halaman atau file JSON) untuk mengambil URL internalnya, sebaiknya delegasikan tugas ini sepenuhnya ke pekerja layanan.
Mendelegasikan jenis operasi ini ke pekerja layanan memiliki keuntungan berikut:
- Mengurangi beban tugas pengambilan dan pemrosesan pasca-pengambilan (yang akan dijelaskan nanti) ke thread sekunder. Dengan begitu, thread utama akan dikosongkan untuk menangani tugas yang lebih penting seperti merespons interaksi pengguna.
- Memungkinkan beberapa klien (misalnya, tab) untuk menggunakan kembali fungsi umum, dan bahkan memanggil layanan secara bersamaan tanpa memblokir thread utama.
Lakukan pra-pengambilan halaman detail produk
Pertama-tama, gunakan postMessage()
di antarmuka pekerja layanan dan teruskan array URL ke cache:
navigator.serviceWorker.controller.postMessage({
type: 'PREFETCH',
payload: {
urls: [
'www.exmaple.com/apis/data_1.json',
'www.exmaple.com/apis/data_2.json',
],
},
});
Pada pekerja layanan, terapkan pengendali message
untuk menangkap 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]);
}
}
});
Dalam kode sebelumnya, kami memperkenalkan fungsi helper 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
}
Setelah respons diperoleh, Anda dapat mengandalkan header caching resource. Namun, sering kali, seperti di halaman detail produk, resource tidak di-cache (yang berarti, resource tersebut memiliki header Cache-control
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 yaitu memungkinkan
file ditayangkan dalam skenario offline.
Lebih dari sekadar data JSON
Setelah diambil dari endpoint server, data JSON sering kali berisi URL lain yang juga layak untuk pengambilan data, seperti gambar atau data endpoint lain yang terkait dengan data level pertama ini.
Anggap saja dalam contoh kita, data JSON yang ditampilkan adalah informasi dari 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 meng-cache banner besar untuk masing-masing 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 menggunakan pekerja layanan untuk pengambilan data adalah tindakan tersebut dapat gagal tanpa banyak konsekuensi terhadap halaman dan thread utama. Anda mungkin juga memiliki logika yang lebih rumit dalam pascapemrosesan konten yang diambil data, sehingga konten tersebut 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 halaman dan pekerja layanan: cache imperatif. Contoh yang dibahas hanya dimaksudkan untuk menunjukkan satu cara menggunakan pola ini. Pendekatan yang sama juga dapat diterapkan pada kasus penggunaan lainnya, misalnya menyimpan artikel teratas dalam cache sesuai permintaan untuk penggunaan offline, bookmark, dan lainnya.
Untuk pola komunikasi halaman dan pekerja layanan lainnya, lihat:
- Menyiarkan update: Memanggil halaman dari pekerja layanan untuk menginformasikan update penting (mis., versi webapp baru tersedia).
- Komunikasi dua arah: Mendelegasikan tugas ke pekerja layanan (misalnya, download yang berat), dan terus memberi tahu halaman tentang progresnya.