Pola pikir pekerja layanan

Cara berpikir saat memikirkan pekerja layanan.

Service worker sangat canggih dan benar-benar layak dipelajari. Fitur ini memungkinkan Anda memberikan tingkat pengalaman yang sama sekali baru kepada pengguna. Situs Anda dapat dimuat secara instan. Aplikasi ini dapat berfungsi secara offline. Aplikasi ini dapat diinstal sebagai aplikasi khusus platform dan terasa sama canggihnya—tetapi dengan jangkauan dan kebebasan web.

Namun, pekerja layanan tidak seperti yang biasa digunakan oleh sebagian besar developer web. Alat ini memiliki kurva belajar yang curam dan beberapa masalah yang harus Anda waspadai.

Developer Google dan saya baru-baru ini berkolaborasi dalam sebuah project—Service Workies—game gratis untuk memahami pekerja layanan. Saat mem-build dan menggunakan seluk-beluk pekerja layanan yang kompleks, saya mengalami beberapa kendala. Hal yang paling membantu saya adalah membuat beberapa metafora deskriptif. Dalam postingan ini, kita akan mempelajari model mental ini dan memahami sifat paradoks yang membuat pekerja layanan menjadi rumit dan luar biasa.

Sama, tetapi berbeda

Saat membuat kode pekerja layanan, banyak hal yang akan terasa familier. Anda dapat menggunakan fitur bahasa JavaScript baru favorit Anda. Anda memproses peristiwa siklus proses seperti halnya peristiwa UI. Anda mengelola alur kontrol dengan promise seperti biasa.

Namun, perilaku pekerja layanan lainnya membuat Anda bingung. Terutama saat Anda memuat ulang halaman dan tidak melihat perubahan kode diterapkan.

Lapisan baru

Biasanya, saat mem-build situs, Anda hanya perlu memikirkan dua lapisan: klien dan server. Service worker adalah lapisan baru yang berada di tengah.

Pekerja layanan bertindak sebagai lapisan tengah antara klien dan server

Anggap pekerja layanan Anda sebagai semacam ekstensi browser—ekstensi yang dapat diinstal situs Anda di browser pengguna. Setelah diinstal, pekerja layanan memperluas browser untuk situs Anda dengan lapisan tengah yang canggih. Lapisan pekerja layanan ini dapat mencegat dan menangani semua permintaan yang dibuat situs Anda.

Lapisan pekerja layanan memiliki siklus prosesnya sendiri yang tidak bergantung pada tab browser. Memuat ulang halaman sederhana tidak cukup untuk mengupdate pekerja layanan—sama seperti Anda tidak mengharapkan pemuatan ulang halaman untuk mengupdate kode yang di-deploy di server. Setiap lapisan memiliki aturan unik untuk pembaruan.

Dalam game Service Workies, kami membahas banyak detail siklus proses pekerja layanan dan memberi Anda banyak latihan untuk menggunakannya.

Efektif, tetapi terbatas

Memiliki pekerja layanan di situs akan memberi Anda manfaat luar biasa. Situs Anda dapat:

  • berfungsi dengan baik meskipun pengguna sedang offline
  • mendapatkan peningkatan performa yang signifikan melalui cache
  • menggunakan notifikasi push
  • dapat diinstal sebagai PWA

Meskipun dapat melakukan banyak hal, pekerja layanan dibatasi oleh desain. Mereka tidak dapat melakukan apa pun secara sinkron atau dalam thread yang sama dengan situs Anda. Artinya, tidak ada akses ke:

  • localStorage
  • DOM
  • jendela

Kabar baiknya, ada beberapa cara agar halaman Anda dapat berkomunikasi dengan pekerja layanannya, termasuk postMessage langsung, Saluran Pesan satu lawan satu, dan Saluran Siaran satu lawan banyak.

Berumur panjang, tetapi berumur pendek

Pekerja layanan aktif akan terus aktif bahkan setelah pengguna keluar dari situs Anda atau menutup tab. Browser menyimpan pekerja layanan ini sehingga akan siap saat pengguna kembali ke situs Anda. Sebelum permintaan pertama dibuat, pekerja layanan mendapatkan kesempatan untuk mencegatnya dan mengambil alih kontrol halaman. Hal inilah yang memungkinkan situs berfungsi secara offline—service worker dapat menayangkan versi halaman yang di-cache, meskipun pengguna tidak memiliki koneksi ke internet.

Di Service Workies, kita memvisualisasikan konsep ini dengan Kolohe (pekerja layanan yang ramah) yang mencegat dan menangani permintaan.

Dihentikan

Meskipun tampak abadi, pekerja layanan dapat dihentikan hampir setiap saat. Browser tidak ingin membuang resource pada pekerja layanan yang saat ini tidak melakukan apa pun. Dihentikan tidak sama dengan dihentikan—pekerja layanan tetap diinstal dan diaktifkan. Perangkat hanya dinonaktifkan. Saat diperlukan lagi (misalnya, untuk menangani permintaan), browser akan mengaktifkannya kembali.

waitUntil

Karena kemungkinan terus-menerus dinonaktifkan, pekerja layanan Anda memerlukan cara untuk memberi tahu browser saat melakukan sesuatu yang penting dan tidak ingin tidur siang. Di sinilah event.waitUntil() berperan. Metode ini memperluas siklus proses tempatnya digunakan, sehingga tidak berhenti dan tidak beralih ke fase berikutnya dalam siklus prosesnya hingga kita siap. Hal ini memberi kita waktu untuk menyiapkan cache, mengambil resource dari jaringan, dll.

Contoh ini memberi tahu browser bahwa penginstalan pekerja layanan belum selesai hingga cache assets dibuat dan diisi dengan gambar pedang:

self.addEventListener("install", event => {
  event.waitUntil(
    caches.open("assets").then(cache => {
      return cache.addAll(["/weapons/sword/blade.png"]);
    })
  );
});

Memperhatikan status global

Saat mulai/berhenti ini terjadi, cakupan global pekerja layanan akan direset. Jadi, berhati-hatilah untuk tidak menggunakan status global apa pun di pekerja layanan Anda atau Anda akan kecewa saat pekerja layanan diaktifkan kembali dan memiliki status yang berbeda dari yang diharapkan.

Perhatikan contoh ini yang menggunakan status global:

const favoriteNumber = Math.random();
let hasHandledARequest = false;

self.addEventListener("fetch", event => {
  console.log(favoriteNumber);
  console.log(hasHandledARequest);
  hasHandledARequest = true;
});

Pada setiap permintaan, pekerja layanan ini akan mencatat nomor—misalnya 0.13981866382421893. Variabel hasHandledARequest juga berubah menjadi true. Sekarang, pekerja layanan tidak ada aktivitasnya selama beberapa saat, sehingga browser menghentikannya. Saat berikutnya ada permintaan, pekerja layanan diperlukan lagi, sehingga browser akan membangunkannya. Skripnya dievaluasi lagi. Sekarang hasHandledARequest direset ke false, dan favoriteNumber adalah sesuatu yang benar-benar berbeda—0.5907281835659033.

Anda tidak dapat mengandalkan status yang disimpan di pekerja layanan. Selain itu, membuat instance seperti Message Channel dapat menyebabkan bug: Anda akan mendapatkan instance baru setiap kali pekerja layanan berhenti/dimulai.

Di Service Worker bab 3, kita memvisualisasikan pekerja layanan yang dihentikan sebagai kehilangan semua warna saat menunggu untuk diaktifkan.

visualisasi service worker yang dihentikan

Bersama, tetapi terpisah

Halaman Anda hanya dapat dikontrol oleh satu pekerja layanan dalam satu waktu. Namun, aplikasi dapat memiliki dua pekerja layanan yang diinstal sekaligus. Saat Anda membuat perubahan pada kode pekerja layanan dan memuat ulang halaman, Anda sebenarnya tidak mengedit pekerja layanan sama sekali. Pekerja layanan immutable. Sebagai gantinya, Anda membuat akun baru. Pekerja layanan baru ini (sebut saja SW2) akan diinstal, tetapi belum akan diaktifkan. Service worker baru harus menunggu hingga service worker saat ini (SW1) dihentikan (saat pengguna meninggalkan situs Anda).

Mengganggu cache pekerja layanan lain

Saat menginstal, SW2 dapat menyiapkan semuanya—biasanya membuat dan mengisi cache. Namun, perhatikan: pekerja layanan baru ini memiliki akses ke semua hal yang dapat diakses oleh pekerja layanan saat ini. Jika Anda tidak berhati-hati, pekerja layanan menunggu baru dapat benar-benar mengacaukan pekerja layanan saat ini. Beberapa contoh yang dapat menyebabkan masalah:

  • SW2 dapat menghapus cache yang aktif digunakan SW1.
  • SW2 dapat mengedit konten cache yang digunakan SW1, sehingga menyebabkan SW1 merespons dengan aset yang tidak diharapkan halaman.

Lewati skipWaiting

Pekerja layanan juga dapat menggunakan metode skipWaiting() yang berisiko untuk mengambil kendali halaman segera setelah selesai diinstal. Hal ini umumnya merupakan ide yang buruk, kecuali jika Anda sengaja mencoba mengganti pekerja layanan yang bermasalah. Service worker baru mungkin menggunakan resource yang diperbarui yang tidak diharapkan halaman saat ini, sehingga menyebabkan error dan bug.

Mulai dari awal

Cara mencegah pekerja layanan saling mengganggu adalah dengan memastikan mereka menggunakan cache yang berbeda. Cara termudah untuk melakukannya adalah dengan membuat versi nama cache yang digunakan.

const version = 1;
const assetCacheName = `assets-${version}`;

self.addEventListener("install", event => {
  caches.open(assetCacheName).then(cache => {
    // confidently do stuff with your very own cache
  });
});

Saat men-deploy pekerja layanan baru, Anda akan mengganti version sehingga dapat melakukan hal yang diperlukan dengan cache yang sepenuhnya terpisah dari pekerja layanan sebelumnya.

visualisasi cache

Pembersihan akhir

Setelah pekerja layanan mencapai status activated, Anda tahu bahwa pekerja layanan tersebut telah mengambil alih, dan pekerja layanan sebelumnya menjadi redundan. Pada tahap ini, Anda harus membersihkan service worker lama. Hal ini tidak hanya mematuhi batas penyimpanan cache pengguna, tetapi juga dapat mencegah bug yang tidak disengaja.

Metode caches.match() adalah pintasan yang sering digunakan untuk mengambil item dari cache mana pun yang cocok. Namun, cache akan di-iterasi sesuai urutan pembuatannya. Jadi, misalnya Anda memiliki dua versi file skrip app.js di dua cache yang berbeda—assets-1 dan assets-2. Halaman Anda mengharapkan skrip yang lebih baru yang disimpan di assets-2. Namun, jika Anda belum menghapus cache lama, caches.match('app.js') akan menampilkan cache lama dari assets-1 dan kemungkinan besar akan merusak situs Anda.

Yang diperlukan untuk membersihkan setelah pekerja layanan sebelumnya adalah menghapus cache yang tidak diperlukan oleh pekerja layanan baru:

const version = 2;
const assetCacheName = `assets-${version}`;

self.addEventListener("activate", event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== assetCacheName){
            return caches.delete(cacheName);
          }
        });
      );
    });
  );
});

Mencegah pekerja layanan Anda saling bertabrakan memerlukan sedikit kerja keras dan disiplin, tetapi hasilnya sepadan.

Pola pikir pekerja layanan

Memahami pola pikir yang tepat saat memikirkan pekerja layanan akan membantu Anda membangunnya dengan percaya diri. Setelah memahaminya, Anda akan dapat menciptakan pengalaman yang luar biasa bagi pengguna.

Jika Anda ingin memahami semua ini dengan memainkan game, Anda beruntung. Mainkan Service Workies tempat Anda akan mempelajari cara kerja service worker untuk mengalahkan monster offline.