Memperkenalkan Pengambilan Latar Belakang

Jake Archibald
Jake Archibald

Pada tahun 2015, kami memperkenalkan Sinkronisasi di Latar Belakang yang memungkinkan pekerja layanan menunda pekerjaan hingga pengguna memiliki konektivitas. Artinya, pengguna dapat mengetik pesan, menekan kirim, dan keluar dari situs dengan mengetahui bahwa pesan akan dikirim sekarang, atau saat mereka memiliki koneksi.

Fitur ini berguna, tetapi memerlukan pekerja layanan agar tetap aktif selama durasi pengambilan data. Hal ini tidak menjadi masalah untuk pekerjaan singkat seperti mengirim pesan, tetapi jika tugas memakan waktu terlalu lama, browser akan menghentikan pekerja layanan, karena hal ini berisiko terhadap privasi dan baterai pengguna.

Jadi, bagaimana jika Anda perlu mendownload sesuatu yang mungkin membutuhkan waktu lama, seperti film, podcast, atau level game. Itulah fungsi Pengambilan Latar Belakang.

Pengambilan Data di Latar Belakang tersedia secara default sejak Chrome 74.

Berikut demo singkat berdurasi dua menit yang menunjukkan keadaan tradisional, dibandingkan dengan menggunakan Background Fetch:

Cara kerjanya

Pengambilan latar belakang berfungsi seperti ini:

  1. Anda memberi tahu browser untuk melakukan sekelompok pengambilan di latar belakang.
  2. Browser mengambil hal-hal tersebut, menampilkan progres kepada pengguna.
  3. Setelah pengambilan selesai atau gagal, browser akan membuka pekerja layanan Anda dan memicu peristiwa untuk memberi tahu Anda apa yang terjadi. Di sini Anda memutuskan apa yang harus dilakukan dengan respons, jika ada.

Jika pengguna menutup halaman situs Anda setelah langkah 1, tidak masalah, download akan tetap berlanjut. Karena pengambilan data sangat terlihat dan dapat dibatalkan dengan mudah, tidak ada masalah privasi terkait tugas sinkronisasi latar belakang yang terlalu lama. Karena service worker tidak terus berjalan, tidak ada kekhawatiran bahwa service worker dapat menyalahgunakan sistem, seperti menambang bitcoin di latar belakang.

Di beberapa platform (seperti Android), browser dapat ditutup setelah langkah 1, karena browser dapat menyerahkan pengambilan ke sistem operasi.

Jika pengguna memulai download saat offline, atau menjadi offline selama download, pengambilan di latar belakang akan dijeda dan dilanjutkan nanti.

API

Deteksi fitur

Seperti fitur baru lainnya, Anda harus mendeteksi apakah browser mendukungnya. Untuk Pengambilan Latar Belakang, caranya sesederhana:

if ('BackgroundFetchManager' in self) {
  // This browser supports Background Fetch!
}

Memulai pengambilan latar belakang

API utama bergantung pada pendaftaran service worker, jadi pastikan Anda telah mendaftarkan service worker terlebih dahulu. Lalu:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
    title: 'Episode 5: Interesting things.',
    icons: [{
      sizes: '300x300',
      src: '/ep-5-icon.png',
      type: 'image/png',
    }],
    downloadTotal: 60 * 1024 * 1024,
  });
});

backgroundFetch.fetch menggunakan tiga argumen:

Parameter
id string
secara unik mengidentifikasi pengambilan data di latar belakang ini.

backgroundFetch.fetch akan menolak jika ID cocok dengan pengambilan latar belakang yang ada.

requests Array<Request|string>
Item yang akan diambil. String akan diperlakukan sebagai URL, dan diubah menjadi Request melalui new Request(theString).

Anda dapat mengambil data dari asal lain selama resource mengizinkannya melalui CORS.

Catatan: Chrome saat ini tidak mendukung permintaan yang memerlukan preflight CORS.

options Objek yang dapat mencakup hal berikut:
options.title string
Judul yang akan ditampilkan browser bersama dengan progres.
options.icons Array<IconDefinition>
Array objek dengan `src`, `size`, dan `type`.
options.downloadTotal number
Ukuran total isi respons (setelah di-unzip).

Meskipun bersifat opsional, sebaiknya Anda memberikan informasi ini. Digunakan untuk memberi tahu pengguna ukuran download dan memberikan informasi progres. Jika Anda tidak menyediakannya, browser akan memberi tahu pengguna bahwa ukuran tidak diketahui, dan akibatnya pengguna mungkin lebih cenderung membatalkan download.

Jika download pengambilan data di latar belakang melebihi jumlah yang diberikan di sini, download akan dibatalkan. Tidak masalah jika download lebih kecil dari downloadTotal, jadi jika Anda tidak yakin berapa total download, sebaiknya berhati-hatilah.

backgroundFetch.fetch menampilkan promise yang di-resolve dengan BackgroundFetchRegistration. Saya akan membahas detailnya nanti. Promise ditolak jika pengguna telah memilih tidak ikut download, atau salah satu parameter yang diberikan tidak valid.

Dengan memberikan banyak permintaan untuk pengambilan latar belakang tunggal, Anda dapat menggabungkan hal-hal yang secara logis merupakan satu hal bagi pengguna. Misalnya, film dapat dibagi menjadi ribuan resource (umumnya dengan MPEG-DASH), dan dilengkapi dengan resource tambahan seperti gambar. Level game dapat tersebar di banyak resource JavaScript, gambar, dan audio. Namun, bagi pengguna, itu hanyalah "film", atau "level".

Mendapatkan pengambilan latar belakang yang ada

Anda bisa mendapatkan pengambilan latar belakang yang ada seperti ini:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

…dengan meneruskan id pengambilan data di latar belakang yang Anda inginkan. get menampilkan undefined jika tidak ada pengambilan di latar belakang yang aktif dengan ID tersebut.

Pengambilan data di latar belakang dianggap "aktif" sejak saat didaftarkan, hingga berhasil, gagal, atau dibatalkan.

Anda bisa mendapatkan daftar semua pengambilan data di latar belakang yang aktif menggunakan getIds:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

Pendaftaran pengambilan latar belakang

BackgroundFetchRegistration (bgFetch dalam contoh di atas) memiliki hal berikut:

Properti
id string
ID pengambilan data di latar belakang.
uploadTotal number
Jumlah byte yang akan dikirim ke server.
uploaded number
Jumlah byte yang berhasil dikirim.
downloadTotal number
Nilai yang diberikan saat pengambilan data di latar belakang didaftarkan, atau nol.
downloaded number
Jumlah byte yang berhasil diterima.

Nilai ini dapat menurun. Misalnya, jika koneksi terputus dan download tidak dapat dilanjutkan, browser akan memulai ulang pengambilan resource tersebut dari awal.

result

Salah satu dari berikut ini:

  • "" - Pengambilan latar belakang aktif, jadi belum ada hasil.
  • "success" - Pengambilan di latar belakang berhasil.
  • "failure" - Pengambilan di latar belakang gagal. Nilai ini hanya muncul saat pengambilan di latar belakang gagal total, seperti saat browser tidak dapat mencoba lagi/melanjutkan.
failureReason

Salah satu dari berikut ini:

  • "" - Pengambilan di latar belakang tidak gagal.
  • "aborted" – Pengambilan data di latar belakang dibatalkan oleh pengguna, atau abort() dipanggil.
  • "bad-status" - Salah satu respons memiliki status tidak oke, misalnya 404.
  • "fetch-error" - Salah satu pengambilan gagal karena alasan lain, misalnya CORS, MIX, respons parsial yang tidak valid, atau kegagalan jaringan umum untuk pengambilan yang tidak dapat dicoba lagi.
  • "quota-exceeded" - Kuota penyimpanan tercapai selama pengambilan di latar belakang.
  • "download-total-exceeded" - `downloadTotal` yang diberikan terlampaui.
recordsAvailable boolean
Dapatkah permintaan/respons pokok diakses?

Jika nilai ini salah (false), match dan matchAll tidak dapat digunakan.

Metode
abort() Menampilkan Promise<boolean>
Membatalkan pengambilan latar belakang.

Promise yang ditampilkan di-resolve dengan nilai benar (true) jika pengambilan berhasil dibatalkan.

matchAll(request, opts) Menampilkan Promise<Array<BackgroundFetchRecord>>
Dapatkan permintaan dan respons.

Argumen di sini sama dengan API cache. Memanggil tanpa argumen akan menampilkan promise untuk semua data.

Lihat di bawah untuk mengetahui detail selengkapnya.

match(request, opts) Menampilkan Promise<BackgroundFetchRecord>
Seperti di atas, tetapi diselesaikan dengan kecocokan pertama.
Acara
progress Diaktifkan saat uploaded, downloaded, result, atau failureReason berubah.

Melacak progres

Hal ini dapat dilakukan melalui peristiwa progress. Ingatlah bahwa downloadTotal adalah nilai apa pun yang Anda berikan, atau 0 jika Anda tidak memberikan nilai.

bgFetch.addEventListener('progress', () => {
  // If we didn't provide a total, we can't provide a %.
  if (!bgFetch.downloadTotal) return;

  const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
  console.log(`Download progress: ${percent}%`);
});

Mendapatkan permintaan dan respons

bgFetch.match('/ep-5.mp3').then(async (record) => {
  if (!record) {
    console.log('No record found');
    return;
  }

  console.log(`Here's the request`, record.request);
  const response = await record.responseReady;
  console.log(`And here's the response`, response);
});

record adalah BackgroundFetchRecord, dan tampilannya seperti ini:

Properti
request Request
Permintaan yang diberikan.
responseReady Promise<Response>
Respons yang diambil.

Respons berada di belakang janji karena mungkin belum diterima. Promise akan ditolak jika pengambilan data gagal.

Peristiwa service worker

Acara
backgroundfetchsuccess Semua data berhasil diambil.
backgroundfetchfailure Satu atau beberapa pengambilan data gagal.
backgroundfetchabort Satu atau beberapa pengambilan data gagal.

Tindakan ini hanya berguna jika Anda ingin melakukan pembersihan data terkait.

backgroundfetchclick Pengguna mengklik UI progres download.

Objek peristiwa memiliki:

Properti
registration BackgroundFetchRegistration
Metode
updateUI({ title, icons }) Memungkinkan Anda mengubah judul/ikon yang Anda tetapkan pada awalnya. Hal ini bersifat opsional, tetapi memungkinkan Anda memberikan lebih banyak konteks jika diperlukan. Anda hanya dapat melakukannya *sekali* selama acara backgroundfetchsuccess dan backgroundfetchfailure.

Bereaksi terhadap keberhasilan/kegagalan

Kita sudah melihat peristiwa progress, tetapi peristiwa tersebut hanya berguna saat pengguna membuka halaman situs Anda. Manfaat utama pengambilan data di latar belakang adalah semuanya terus berfungsi setelah pengguna keluar dari halaman, atau bahkan menutup browser.

Jika pengambilan di latar belakang berhasil diselesaikan, pekerja layanan Anda akan menerima peristiwa backgroundfetchsuccess, dan event.registration akan menjadi pendaftaran pengambilan di latar belakang.

Setelah peristiwa ini, permintaan dan respons yang diambil tidak lagi dapat diakses, jadi jika Anda ingin menyimpannya, pindahkan ke suatu tempat seperti cache API.

Seperti sebagian besar peristiwa pekerja layanan, gunakan event.waitUntil agar pekerja layanan mengetahui kapan peristiwa selesai.

Misalnya, di pekerja layanan Anda:

addEventListener('backgroundfetchsuccess', (event) => {
  const bgFetch = event.registration;

  event.waitUntil(async function() {
    // Create/open a cache.
    const cache = await caches.open('downloads');
    // Get all the records.
    const records = await bgFetch.matchAll();
    // Copy each request/response across.
    const promises = records.map(async (record) => {
      const response = await record.responseReady;
      await cache.put(record.request, response);
    });

    // Wait for the copying to complete.
    await Promise.all(promises);

    // Update the progress notification.
    event.updateUI({ title: 'Episode 5 ready to listen!' });
  }());
});

Kegagalan mungkin disebabkan oleh satu error 404, yang mungkin tidak penting bagi Anda, jadi mungkin masih ada baiknya menyalin beberapa respons ke dalam cache seperti di atas.

Bereaksi terhadap klik

UI yang menampilkan progres dan hasil download dapat diklik. Peristiwa backgroundfetchclick di service worker memungkinkan Anda bereaksi terhadap hal ini. Seperti di atas, event.registration akan menjadi pendaftaran pengambilan latar belakang.

Hal umum yang dapat dilakukan dengan acara ini adalah membuka jendela:

addEventListener('backgroundfetchclick', (event) => {
  const bgFetch = event.registration;

  if (bgFetch.result === 'success') {
    clients.openWindow('/latest-podcasts');
  } else {
    clients.openWindow('/download-progress');
  }
});

Referensi lainnya

Koreksi: Versi sebelumnya dari artikel ini keliru menyebutkan bahwa Background Fetch adalah "standar web". Saat ini, API tidak berada di jalur standar, spesifikasi dapat ditemukan di WICG sebagai Laporan Grup Komunitas Draf.