Memperkenalkan Pengambilan Latar Belakang

Jake Archibald
Jake Archibald

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

Ini adalah fitur yang berguna, tetapi mengharuskan pekerja layanan aktif selama pengambilan. Hal ini tidak menjadi masalah untuk pekerjaan singkat seperti mengirim pesan, tetapi jika tugas tersebut memakan waktu terlalu lama, browser akan menghentikan pekerja layanan. Jika tidak, hal ini akan membahayakan privasi dan baterai pengguna.

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

Pengambilan Latar Belakang tersedia secara default sejak Chrome 74.

Berikut demo singkat dua menit yang menunjukkan status tradisional berbagai hal, dibandingkan menggunakan Pengambilan Latar Belakang:

Coba demonya sendiri dan jelajahi kodenya.

Cara kerjanya

Pengambilan latar belakang berfungsi seperti ini:

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

Jika pengguna menutup halaman ke situs Anda setelah langkah 1, tidak masalah, download akan dilanjutkan. Karena pengambilan sangat terlihat dan mudah dibatalkan, tidak ada masalah privasi terkait tugas sinkronisasi latar belakang yang terlalu lama. Karena pekerja layanan tidak terus berjalan, tidak ada kekhawatiran bahwa layanan tersebut dapat menyalahgunakan sistem, seperti menambang bitcoin di latar belakang.

Pada 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 offline selama download, pengambilan latar belakang akan dijeda dan dilanjutkan nanti.

API

Deteksi fitur

Seperti fitur baru lainnya, Anda sebaiknya mendeteksi apakah browser mendukungnya atau tidak. Untuk Pengambilan Latar Belakang, caranya sederhana:

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

Memulai pengambilan latar belakang

API utama menghentikan pendaftaran pekerja layanan, jadi pastikan Anda telah mendaftarkan pekerja layanan 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 latar belakang ini.

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

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

Anda dapat mengambil berbagai hal dari origin lain selama resource mengizinkannya melalui CORS.

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

options Objek yang dapat menyertakan hal berikut:
options.title string
Judul untuk ditampilkan browser beserta progresnya.
options.icons Array<IconDefinition>
Array objek dengan `src`, `size`, dan `type`.
options.downloadTotal number
Ukuran total isi respons (setelah diekstrak).

Meskipun bersifat opsional, sebaiknya Anda memberikannya. Atribut ini digunakan untuk memberi tahu pengguna seberapa besar downloadnya, dan untuk memberikan informasi progres. Jika Anda tidak memberikan atribut ini, browser akan memberi tahu pengguna bahwa ukuran file tidak diketahui, dan akibatnya pengguna mungkin cenderung akan membatalkan download.

Jika download pengambilan latar belakang melebihi jumlah yang diberikan di sini, proses akan dibatalkan. Tidak masalah jika ukuran download lebih kecil dari downloadTotal, jadi jika Anda tidak yakin berapa total downloadnya, sebaiknya jangan mengambil risiko.

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

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

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 latar belakang yang Anda inginkan. get menampilkan undefined jika tidak ada pengambilan latar belakang yang aktif dengan ID tersebut.

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

Anda bisa mendapatkan daftar semua pengambilan 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 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 latar belakang didaftarkan, atau nol.
downloaded number
Jumlah byte yang berhasil diterima.

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

result

Salah satu dari berikut ini:

  • "" - Pengambilan latar belakang aktif, sehingga belum ada hasil.
  • "success" - Pengambilan latar belakang berhasil.
  • "failure" - Pengambilan latar belakang gagal. Nilai ini hanya muncul jika pengambilan latar belakang benar-benar gagal, karena browser tidak dapat mencoba lagi/dilanjutkan.
failureReason

Salah satu dari berikut ini:

  • "" - Pengambilan latar belakang belum gagal.
  • "aborted" – Pengambilan latar belakang dibatalkan oleh pengguna, atau abort() dipanggil.
  • "bad-status" - Salah satu respons memiliki status tidak baik, 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 latar belakang.
  • "download-total-exceeded" - Jumlah `downloadTotal` yang diberikan terlampaui.
recordsAvailable boolean
Apakah permintaan/respons yang mendasarinya dapat diakses?

Jika nilainya salah, match dan matchAll tidak dapat digunakan.

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

Promise yang ditampilkan akan di-resolve dengan true jika pengambilan berhasil dibatalkan.

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

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

Lihat di bawah untuk detail selengkapnya.

match(request, opts) Menampilkan Promise<BackgroundFetchRecord>
Seperti di atas, tetapi me-resolve dengan kecocokan pertama.
Peristiwa
progress Diaktifkan saat salah satu dari uploaded, downloaded, result, atau failureReason berubah.

Melacak progres

Tindakan ini dapat dilakukan melalui peristiwa progress. Ingat 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 terlihat seperti ini:

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

Respons berada di balik promise karena mungkin belum diterima. Promise akan ditolak jika pengambilan gagal.

Peristiwa pekerja layanan

Peristiwa
backgroundfetchsuccess Semuanya berhasil diambil.
backgroundfetchfailure Satu atau beberapa pengambilan gagal.
backgroundfetchabort Satu atau beberapa pengambilan gagal.

Langkah ini hanya sangat berguna jika Anda ingin melakukan pembersihan data terkait.

backgroundfetchclick Pengguna mengklik UI progres download.

Objek peristiwa memiliki hal berikut:

Properti
registration BackgroundFetchRegistration
Metode
updateUI({ title, icons }) Memungkinkan Anda mengubah judul/ikon yang awalnya ditetapkan. Cara ini bersifat opsional, tetapi Anda dapat memberikan lebih banyak konteks jika diperlukan. Anda hanya dapat melakukan ini *sekali* selama peristiwa backgroundfetchsuccess dan backgroundfetchfailure.

Bereaksi terhadap keberhasilan/kegagalan

Kita telah melihat peristiwa progress, tetapi peristiwa tersebut hanya berguna saat pengguna membuka halaman situs Anda. Manfaat utama dari pengambilan latar belakang adalah fitur akan terus berfungsi setelah pengguna meninggalkan halaman, atau bahkan menutup browser.

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

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

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

Misalnya, dalam pekerja layanan:

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 bermuara pada satu 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 download dan hasil yang dapat diklik. Peristiwa backgroundfetchclick di pekerja layanan memungkinkan Anda bereaksi terhadap hal ini. Seperti di atas, event.registration akan menjadi pendaftaran pengambilan di latar belakang.

Hal umum yang dapat dilakukan dengan peristiwa 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 salah menyebut Pengambilan Latar Belakang sebagai "standar web". API saat ini tidak berada di jalur standar, spesifikasi dapat ditemukan di WICG sebagai Draf Laporan Grup Komunitas.