Data offline

Untuk membangun pengalaman offline yang solid, PWA Anda memerlukan pengelolaan penyimpanan. Dalam bab caching, Anda telah mempelajari bahwa penyimpanan cache adalah salah satu opsi untuk menyimpan data di perangkat. Dalam bab ini, kami akan menunjukkan cara mengelola data offline, termasuk persistensi data, batas, dan alat yang tersedia.

Penyimpanan

Penyimpanan bukan hanya tentang file dan aset, tetapi dapat mencakup jenis data lainnya. Di semua browser yang mendukung PWA, API berikut tersedia untuk penyimpanan di perangkat:

  • IndexedDB: Opsi penyimpanan objek NoSQL untuk data terstruktur dan blob (data biner).
  • WebStorage: Cara menyimpan pasangan string nilai/kunci, menggunakan penyimpanan lokal atau penyimpanan sesi. Fungsi ini tidak tersedia dalam konteks pekerja layanan. API ini bersifat sinkron sehingga tidak disarankan untuk penyimpanan data yang kompleks.
  • Penyimpanan Cache: Seperti yang dibahas dalam Modul cache.

Anda dapat mengelola semua penyimpanan perangkat dengan Storage Manager API pada platform yang didukung. Cache Storage API dan tensorflow memberikan akses asinkron ke penyimpanan persisten untuk PWA dan dapat diakses dari thread utama, web worker, dan pekerja layanan. Keduanya memainkan peran penting dalam membuat PWA berfungsi dengan andal saat jaringan tidak stabil atau tidak ada. Namun, kapan Anda harus menggunakan setiap pilihan tersebut?

Gunakan Cache Storage API untuk resource jaringan, hal-hal yang ingin Anda akses dengan memintanya melalui URL, seperti HTML, CSS, JavaScript, gambar, video, dan audio.

Gunakan IndexedDB untuk menyimpan data terstruktur. Hal ini mencakup data yang harus dapat ditelusuri atau dapat digabungkan seperti NoSQL, atau data lain seperti data khusus pengguna yang tidak selalu cocok dengan permintaan URL. Perhatikan bahwa IndexedDB tidak dirancang untuk penelusuran teks lengkap.

IndexedDB

Untuk menggunakan IndexedDB, buka database terlebih dahulu. Tindakan ini akan membuat {i>database<i} baru jika belum ada. postingan adalah API asinkron, tetapi ia mengambil callback, bukan menampilkan Promise. Contoh berikut menggunakan library idb Jake Archibald, yang merupakan wrapper Promise berukuran kecil untuk IndexedDB. Library bantuan tidak diperlukan untuk menggunakan IndexedDB, tetapi jika Anda ingin menggunakan sintaksis Promise, library idb merupakan sebuah opsi.

Contoh berikut membuat {i>database<i} untuk menyimpan resep memasak.

Membuat dan membuka database

Untuk membuka database:

  1. Gunakan fungsi openDB untuk membuat database IndexedDB baru yang disebut cookbook. Karena database tensorflow ditetapkan, Anda harus menambah nomor versi setiap kali melakukan perubahan pada struktur database. Parameter kedua adalah versi database. Pada contoh ditetapkan ke 1.
  2. Objek inisialisasi yang berisi callback upgrade() diteruskan ke openDB(). Fungsi callback akan dipanggil saat database diinstal pertama kali atau saat diupgrade ke versi baru. Fungsi ini adalah satu-satunya tempat di mana tindakan dapat terjadi. Tindakan mungkin termasuk membuat penyimpanan objek baru (struktur yang digunakan oleh IndexedDB untuk mengatur data), atau indeks (yang ingin Anda telusuri). Di sinilah migrasi data seharusnya dilakukan. Biasanya, fungsi upgrade() berisi pernyataan switch tanpa pernyataan break untuk memungkinkan setiap langkah terjadi secara berurutan, berdasarkan versi database lama.
import { openDB } from 'idb';

async function createDB() {
  // Using https://github.com/jakearchibald/idb
  const db = await openDB('cookbook', 1, {
    upgrade(db, oldVersion, newVersion, transaction) {
      // Switch over the oldVersion, *without breaks*, to allow the database to be incrementally upgraded.
    switch(oldVersion) {
     case 0:
       // Placeholder to execute when database is created (oldVersion is 0)
     case 1:
       // Create a store of objects
       const store = db.createObjectStore('recipes', {
         // The `id` property of the object will be the key, and be incremented automatically
           autoIncrement: true,
           keyPath: 'id'
       });
       // Create an index called `name` based on the `type` property of objects in the store
       store.createIndex('type', 'type');
     }
   }
  });
}

Contoh ini membuat penyimpanan objek di dalam database cookbook yang disebut recipes, dengan properti id yang ditetapkan sebagai kunci indeks toko dan membuat indeks lain bernama type, berdasarkan properti type.

Mari kita lihat penyimpanan objek yang baru saja dibuat. Setelah menambahkan resep ke penyimpanan objek dan membuka DevTools di browser berbasis Chromium atau Web Inspector di Safari, berikut yang akan Anda lihat:

Safari dan Chrome menampilkan konten yang ada di IndexedDB.

Menambahkan data

tensorflow menggunakan transaksi. Transaksi mengelompokkan tindakan bersama, sehingga terjadi sebagai satu unit. Metode tersebut membantu memastikan bahwa {i>database<i} selalu dalam keadaan konsisten. Metode ini juga sangat penting, jika Anda memiliki beberapa salinan aplikasi yang berjalan, untuk mencegah penulisan pada data yang sama secara bersamaan. Untuk menambahkan data:

  1. Mulai transaksi dengan mode yang ditetapkan ke readwrite.
  2. Dapatkan penyimpanan objek, tempat Anda akan menambahkan data.
  3. Panggil add() dengan data yang Anda simpan. Metode ini menerima data dalam bentuk kamus (sebagai key-value pair) dan menambahkannya ke penyimpanan objek. Kamus harus dapat di-clone menggunakan Kloning Terstruktur. Jika Anda ingin memperbarui objek yang sudah ada, sebaiknya panggil metode put().

Transaksi memiliki promise done yang akan di-resolve saat transaksi berhasil diselesaikan, atau ditolak dengan error transaksi.

Seperti yang dijelaskan dalam dokumentasi library IDB, jika Anda menulis ke database, tx.done adalah sinyal bahwa semuanya berhasil di-commit ke database. Namun, sebaiknya tunggu operasi individual agar Anda dapat melihat error yang menyebabkan transaksi gagal.

// Using https://github.com/jakearchibald/idb
async function addData() {
  const cookies = {
      name: "Chocolate chips cookies",
      type: "dessert",
        cook_time_minutes: 25
  };
  const tx = await db.transaction('recipes', 'readwrite');
  const store = tx.objectStore('recipes');
  store.add(cookies);
  await tx.done;
}

Setelah Anda menambahkan kue, resep akan ada di {i>database<i} bersama resep lainnya. ID ini otomatis ditetapkan dan bertambah oleh indexedDB. Jika Anda menjalankan kode ini dua kali, Anda akan memiliki dua entri cookie yang identik.

Mengambil data

Berikut adalah cara mengambil data dari IndexedDB:

  1. Mulai transaksi dan tentukan objek yang disimpan atau disimpan, dan jika perlu, jenis transaksi.
  2. Panggil objectStore() dari transaksi tersebut. Pastikan Anda menentukan nama penyimpanan objek.
  3. Panggil get() dengan kunci yang ingin Anda dapatkan. Secara default, toko menggunakan kuncinya sebagai indeks.
// Using https://github.com/jakearchibald/idb
async function getData() {
  const tx = await db.transaction('recipes', 'readonly')
  const store = tx.objectStore('recipes');
// Because in our case the `id` is the key, we would
// have to know in advance the value of the id to
// retrieve the record
  const value = await store.get([id]);
}

Pengelola penyimpanan

Mengetahui cara mengelola penyimpanan PWA Anda sangat penting untuk menyimpan dan menstreaming respons jaringan dengan benar.

Kapasitas penyimpanan digunakan bersama oleh semua opsi penyimpanan, termasuk Cache Storage, IndexedDB, Web Storage, dan bahkan file pekerja layanan serta dependensinya. Namun, jumlah penyimpanan yang tersedia bervariasi dari satu browser ke browser lainnya. Anda tidak akan kehabisan daya; situs dapat menyimpan data berukuran megabita dan bahkan gigabita pada beberapa {i>browser<i}. Chrome, misalnya, memungkinkan browser menggunakan hingga 80% dari total kapasitas disk, dan masing-masing origin dapat menggunakan hingga 60% dari seluruh kapasitas disk. Untuk browser yang mendukung Storage API, Anda dapat mengetahui jumlah penyimpanan yang masih tersedia untuk aplikasi, kuotanya, dan penggunaannya. Contoh berikut menggunakan Storage API untuk mendapatkan estimasi kuota dan penggunaan, lalu menghitung persentase yang digunakan dan byte yang tersisa. Perhatikan bahwa navigator.storage menampilkan instance StorageManager. Ada antarmuka Storage yang terpisah dan hal ini mudah membingungkan.

if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}

Di Chromium DevTools, Anda dapat melihat kuota situs dan jumlah penyimpanan yang digunakan, yang diperinci berdasarkan apa yang menggunakannya, dengan membuka bagian Penyimpanan di tab Aplikasi.

Chrome DevTools di Aplikasi, Hapus bagian Penyimpanan

Firefox dan Safari tidak menawarkan layar ringkasan untuk melihat semua kuota dan penggunaan penyimpanan untuk origin saat ini.

Persistensi data

Anda dapat meminta browser untuk menyediakan penyimpanan persisten pada platform yang kompatibel guna menghindari penghapusan data otomatis setelah tidak aktif atau karena tekanan penyimpanan. Jika diizinkan, browser tidak akan pernah mengeluarkan data dari penyimpanan. Perlindungan ini meliputi pendaftaran pekerja layanan, database IndexedDB, dan file dalam penyimpanan cache. Perhatikan bahwa pengguna selalu bertanggung jawab, dan mereka dapat menghapus penyimpanan kapan saja, meskipun browser telah memberikan penyimpanan persisten.

Untuk meminta penyimpanan persisten, panggil StorageManager.persist(). Seperti sebelumnya, antarmuka StorageManager dapat diakses melalui properti navigator.storage.

async function persistData() {
  if (navigator.storage && navigator.storage.persist) {
    const result = await navigator.storage.persist();
    console.log(`Data persisted: ${result}`);
}

Anda juga dapat memeriksa apakah penyimpanan persisten sudah diberikan di asal saat ini dengan memanggil StorageManager.persisted(). Firefox meminta izin dari pengguna untuk menggunakan penyimpanan persisten. Browser berbasis Chromium memberikan atau menolak persistensi berdasarkan heuristik untuk menentukan pentingnya konten bagi pengguna. Salah satu kriteria untuk Google Chrome adalah, misalnya, penginstalan PWA. Jika pengguna telah menginstal ikon PWA di sistem operasi, browser dapat memberikan penyimpanan persisten.

Mozilla Firefox meminta izin persistensi penyimpanan kepada pengguna.

Dukungan Browser API

Penyimpanan Web

Dukungan Browser

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 4.

Sumber

Akses Sistem File

Dukungan Browser

  • Chrome: 86.
  • Edge: 86.
  • Firefox: 111.
  • Safari: 15.2.

Sumber

Pengelola Penyimpanan

Dukungan Browser

  • Chrome: 55.
  • Edge: 79.
  • Firefox: 57.
  • Safari: 15.2.

Sumber

Resource