Masa pakai pekerja layanan

Sulit untuk mengetahui apa yang dilakukan pekerja layanan tanpa memahami siklus prosesnya. Cara kerja internal mereka akan tampak buram, bahkan sewenang-wenang. Sebaiknya ingat bahwa—seperti API browser lainnya—perilaku pekerja layanan didefinisikan dengan baik, tertentu, dan memungkinkan aplikasi {i>offline<i}, sekaligus memfasilitasi pembaruan tanpa mengganggu pengalaman pengguna.

Sebelum masuk ke {i>Workbox<i}, penting untuk memahami siklus proses pekerja layanan sehingga apa yang dilakukan Workbox dapat dimengerti.

Menentukan istilah

Sebelum masuk ke siklus hidup pekerja layanan, ada baiknya untuk mendefinisikan beberapa istilah tentang bagaimana siklus hidup itu beroperasi.

Kontrol dan ruang lingkup

Gagasan tentang kontrol penting untuk memahami cara pekerja layanan beroperasi. Halaman yang dideskripsikan sebagai dikontrol oleh pekerja layanan adalah halaman yang memungkinkan pekerja layanan mencegat permintaan jaringan atas nama halaman tersebut. Pekerja layanan ada dan dapat melakukan pekerjaan untuk halaman dalam cakupan tertentu.

Cakupan

Cakupan pekerja layanan ditentukan oleh lokasinya di server web. Jika pekerja layanan berjalan pada halaman yang terletak di /subdir/index.html, dan berada di /subdir/sw.js, cakupan pekerja layanan adalah /subdir/. Untuk melihat penerapan konsep ruang lingkup, lihat contoh berikut:

  1. Buka https://service-worker-scope-viewer.glitch.me/subdir/index.html. Akan muncul pesan yang menyatakan tidak ada pekerja layanan yang mengontrol halaman. Namun, halaman tersebut mendaftarkan pekerja layanan dari https://service-worker-scope-viewer.glitch.me/subdir/sw.js.
  2. Muat ulang halaman. Karena pekerja layanan telah terdaftar dan sekarang aktif, tapi sedang mengontrol halaman. Formulir yang berisi cakupan pekerja layanan, status saat ini, dan URL-nya akan terlihat. Catatan: memuat ulang halaman tidak ada hubungannya dengan melainkan siklus hidup pekerja layanan, yang akan dijelaskan nanti.
  3. Sekarang, buka https://service-worker-scope-viewer.glitch.me/index.html. Meskipun pekerja layanan telah terdaftar di asal ini, masih ada pesan yang mengatakan tidak ada pekerja layanan saat ini. Itu karena halaman ini tidak berada dalam cakupan pekerja layanan terdaftar.

Cakupan membatasi halaman apa saja yang dikontrol pekerja layanan. Dalam contoh ini, artinya pekerja layanan yang dimuat dari /subdir/sw.js hanya dapat mengontrol halaman yang berada di /subdir/ atau subhierarkinya.

Di atas adalah cara kerja pencakupan secara {i>default<i}, tapi cakupan maksimum yang diizinkan dapat diganti dengan menetapkan Header respons Service-Worker-Allowed, serta meneruskan Opsi scope ke metode register.

Kecuali ada alasan yang sangat bagus untuk membatasi cakupan pekerja layanan ke subset origin, memuat pekerja layanan dari direktori {i> root<i} server web sehingga cakupannya seluas mungkin, dan tidak perlu mengkhawatirkan header Service-Worker-Allowed. Akan jauh lebih sederhana bagi semua orang dengan begitu.

Klien

Ketika dikatakan bahwa pekerja layanan mengontrol laman, sebenarnya itu adalah mengontrol klien. Klien adalah setiap halaman terbuka yang URL-nya berada dalam cakupan pekerja layanan tersebut. Secara khusus, ini adalah instance WindowClient.

Siklus proses pekerja layanan baru

Agar pekerja layanan dapat mengontrol halaman, bisa dikatakan, ide itu harus terwujud terlebih dahulu. Mari kita mulai dengan apa yang terjadi ketika pekerja layanan baru di-deploy untuk situs tanpa pekerja layanan aktif.

Pendaftaran

Pendaftaran adalah langkah awal dari siklus proses pekerja layanan:

<!-- In index.html, for example: -->
<script>
  // Don't register the service worker
  // until the page has fully loaded
  window.addEventListener('load', () => {
    // Is service worker available?
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/sw.js').then(() => {
        console.log('Service worker registered!');
      }).catch((error) => {
        console.warn('Error registering service worker:');
        console.warn(error);
      });
    }
  });
</script>

Kode ini berjalan di thread utama dan melakukan hal berikut:

  1. Karena kunjungan pertama pengguna ke situs web terjadi tanpa pekerja layanan yang terdaftar, tunggu hingga laman dimuat sepenuhnya sebelum mendaftarkannya. Hal ini untuk menghindari pertentangan bandwidth jika pekerja layanan melakukan pra-cache apa pun.
  2. Meskipun pekerja layanan didukung dengan baik, pemeriksaan cepat membantu menghindari {i>error<i} di browser yang tidak mendukungnya.
  3. Saat halaman dimuat sepenuhnya, dan jika pekerja layanan didukung, daftarkan /sw.js.

Beberapa hal penting yang perlu dipahami adalah:

  • Service worker berfungsi hanya tersedia melalui HTTPS atau localhost.
  • Jika konten pekerja layanan mengandung kesalahan {i>syntax<i}, pendaftaran gagal dan pekerja layanan dihapus.
  • Pengingat: pekerja layanan beroperasi dalam ruang lingkup. Di sini, cakupannya adalah seluruh origin, karena dimuat dari direktori root.
  • Saat pendaftaran dimulai, status pekerja layanan akan disetel ke 'installing'.

Setelah pendaftaran selesai, penginstalan dimulai.

Penginstalan

Seorang pekerja layanan memicu Peristiwa install setelah pendaftaran. install hanya dipanggil sekali per pekerja layanan, dan tidak akan diaktifkan lagi sampai di-update. Callback untuk peristiwa install dapat didaftarkan dalam cakupan pekerja dengan addEventListener:

// /sw.js
self.addEventListener('install', (event) => {
  const cacheKey = 'MyFancyCacheName_v1';

  event.waitUntil(caches.open(cacheKey).then((cache) => {
    // Add all the assets in the array to the 'MyFancyCacheName_v1'
    // `Cache` instance for later use.
    return cache.addAll([
      '/css/global.bc7b80b7.css',
      '/css/home.fe5d0b23.css',
      '/js/home.d3cc4ba4.js',
      '/js/jquery.43ca4933.js'
    ]);
  }));
});

Tindakan ini akan membuat instance Cache baru dan melakukan precache aset. Nanti, kita akan memiliki banyak kesempatan untuk membahas {i>precaching<i}, jadi mari kita fokus pada peran event.waitUntil event.waitUntil menerima promise, dan menunggu sampai janji itu diselesaikan. Dalam contoh ini, promise tersebut melakukan dua hal asinkron:

  1. Membuat instance Cache baru bernama 'MyFancyCache_v1'.
  2. Setelah {i>cache<i} dibuat, array URL aset di-pra-cache menggunakan atribut Metode addAll.

Penginstalan akan gagal jika promise yang diteruskan ke event.waitUntil ditolak. Jika ini terjadi, pekerja layanan akan dihapus.

Jika promise diselesaikan, penginstalan berhasil dan status pekerja layanan akan berubah menjadi 'installed' lalu akan diaktifkan.

Aktivasi

Jika pendaftaran dan instalasi berhasil, pekerja layanan diaktifkan, dan statusnya menjadi 'activating' Pekerjaan dapat dilakukan selama aktivasi dalam lingkungan Peristiwa activate. Tugas umum dalam peristiwa ini adalah memangkas {i>cache<i} lama, tapi untuk pekerja layanan baru, hal ini tidak relevan untuk saat ini, dan akan diperluas pada saat kita membahas update pekerja layanan.

Untuk pekerja layanan baru, activate diaktifkan tepat setelah install berhasil. Setelah aktivasi selesai, status pekerja layanan menjadi 'activated'. Perhatikan bahwa, secara {i>default<i}, pekerja layanan baru tidak akan mulai mengontrol halaman sampai navigasi atau pemuatan ulang halaman berikutnya.

Menangani update pekerja layanan

Setelah pekerja layanan pertama di-deploy, data itu kemungkinan perlu diperbarui nanti. Misalnya, update mungkin diperlukan jika terjadi perubahan dalam penanganan permintaan atau logika precaching.

Kapan update dilakukan

Browser akan memeriksa update untuk pekerja layanan jika:

  • Pengguna membuka halaman dalam cakupan pekerja layanan.
  • navigator.serviceWorker.register() dipanggil dengan URL yang berbeda dari pekerja layanan yang saat ini diinstal—tetapi jangan mengubah URL pekerja layanan.
  • navigator.serviceWorker.register() dipanggil dengan URL yang sama dengan pekerja layanan yang terinstal, tetapi dengan cakupan yang berbeda. Sekali lagi, hindari hal ini dengan menjaga ruang lingkup tetap berada di akar asal (root of origin) jika memungkinkan.
  • Ketika peristiwa seperti 'push' atau 'sync' telah dipicu dalam 24 jam terakhir—tetapi jangan khawatir tentang peristiwa ini.

Cara pembaruan dilakukan

Mengetahui kapan browser memperbarui pekerja layanan adalah hal penting, tapi begitu juga dengan "{i>How<i}". Dengan asumsi URL atau cakupan pekerja layanan tidak berubah, pekerja layanan yang saat ini terinstal hanya akan diperbarui ke versi baru jika isinya telah berubah.

Browser mendeteksi perubahan dengan beberapa cara:

  • Setiap perubahan byte-untuk-byte pada skrip yang diminta oleh importScripts, jika berlaku.
  • Setiap perubahan dalam kode tingkat atas pekerja layanan, yang mempengaruhi sidik jari yang dihasilkan oleh browser.

Browser melakukan banyak tugas berat di sini. Untuk memastikan browser memiliki semua yang dibutuhkan untuk mendeteksi perubahan konten pekerja layanan secara andal, tidak memberi tahu {i>cache<i} HTTP untuk menyimpannya, dan jangan mengubah nama filenya. Browser secara otomatis melakukan pemeriksaan update jika ada navigasi ke halaman baru dalam cakupan pekerja layanan.

Memicu pemeriksaan update secara manual

Terkait pembaruan, logika pendaftaran umumnya tidak boleh berubah. Namun, satu pengecualian mungkin berlaku jika sesi di situs berumur panjang. Hal ini dapat terjadi pada aplikasi web satu halaman di mana permintaan navigasi jarang terjadi, karena aplikasi biasanya menemui satu permintaan navigasi di awal siklus proses aplikasi. Dalam situasi seperti ini, update manual dapat dipicu di thread utama:

navigator.serviceWorker.ready.then((registration) => {
  registration.update();
});

Untuk {i>website<i} tradisional, atau dalam kasus apa pun di mana sesi pengguna tidak berumur panjang, memicu pembaruan manual mungkin tidak diperlukan.

Penginstalan

Saat menggunakan pemaket untuk menghasilkan aset statis, aset tersebut akan berisi {i>hash <i} dalam namanya, misalnya framework.3defa9d2.js. Misalkan beberapa aset tersebut di-pra-cache untuk akses offline nanti. Langkah ini akan memerlukan update pekerja layanan untuk melakukan pra-cache aset yang diperbarui:

self.addEventListener('install', (event) => {
  const cacheKey = 'MyFancyCacheName_v2';

  event.waitUntil(caches.open(cacheKey).then((cache) => {
    // Add all the assets in the array to the 'MyFancyCacheName_v2'
    // `Cache` instance for later use.
    return cache.addAll([
      '/css/global.ced4aef2.css',
      '/css/home.cbe409ad.css',
      '/js/home.109defa4.js',
      '/js/jquery.38caf32d.js'
    ]);
  }));
});

Dua hal berbeda dengan contoh peristiwa install pertama dari sebelumnya:

  1. Instance Cache baru dengan kunci 'MyFancyCacheName_v2' dibuat.
  2. Nama aset yang telah di-pra-cache telah berubah.

Satu hal yang perlu diperhatikan adalah bahwa pekerja layanan yang telah diupdate akan diinstal bersama dengan yang sebelumnya. Ini berarti pekerja layanan lama masih memegang kendali atas setiap halaman yang terbuka, dan setelah penginstalan, yang baru memasuki status tunggu hingga diaktifkan.

Secara default, pekerja layanan baru akan diaktifkan saat tidak ada klien yang dikontrol oleh yang lama. Hal ini terjadi saat semua tab terbuka untuk situs yang relevan ditutup.

Aktivasi

Ketika pekerja layanan yang diperbarui diinstal dan fase tunggu berakhir, diaktifkan, dan pekerja layanan yang lama dibuang. Tugas umum yang harus dilakukan dalam peristiwa activate pekerja layanan yang diupdate adalah memangkas cache lama. Hapus cache lama dengan mendapatkan kunci untuk semua instance Cache yang terbuka dengan caches.keys dan menghapus {i>cache<i} yang tidak ada di daftar yang diizinkan yang didefinisikan dengan caches.delete:

self.addEventListener('activate', (event) => {
  // Specify allowed cache keys
  const cacheAllowList = ['MyFancyCacheName_v2'];

  // Get all the currently active `Cache` instances.
  event.waitUntil(caches.keys().then((keys) => {
    // Delete all caches that aren't in the allow list:
    return Promise.all(keys.map((key) => {
      if (!cacheAllowList.includes(key)) {
        return caches.delete(key);
      }
    }));
  }));
});

Cache lama tidak selesai rapi. Kita perlu melakukannya sendiri atau berisiko melebihi kuota penyimpanan. Karena 'MyFancyCacheName_v1' dari pekerja layanan pertama sudah usang, daftar yang diizinkan cache diperbarui untuk menentukan 'MyFancyCacheName_v2', yang menghapus {i>cache<i} dengan nama yang berbeda.

Peristiwa activate akan selesai setelah cache lama dihapus. Pada tahap ini, pekerja layanan baru akan mengambil alih halaman, akhirnya mengganti yang lama!

Siklus proses terus berjalan

Apakah Workbox digunakan untuk menangani deployment dan update pekerja layanan, atau jika Service Worker API digunakan secara langsung, ada untungnya untuk memahami siklus proses pekerja layanan. Dengan pemahaman itu, perilaku pekerja layanan seharusnya tampak lebih logis daripada misterius.

Bagi mereka yang tertarik untuk mempelajari subjek ini lebih dalam, ada baiknya untuk melihat artikel ini oleh Jake Archibald. Ada banyak perbedaan dalam bagaimana keseluruhan tarian di sekitar siklus hidup layanan berjalan, tapi umumnya dapat diketahui, dan pengetahuan tersebut akan sangat bermanfaat saat menggunakan Workbox.