Kodeloka
  1. Kodeloka
  2. Kelas JavaScript
  3. Materi

4 · DOM & Peramban · Modul 15 dari 22

Penyimpanan Data di Peramban: localStorage, sessionStorage, dan IndexedDB

Menyimpan state aplikasi di sisi klien menggunakan Web Storage API (localStorage dan sessionStorage), membungkus serialisasi JSON dengan aman, menyinkronkan data antar-tab dengan event storage, serta memilih antara Web Storage, IndexedDB, dan HTTP Cookie.

Memilih Mekanisme Penyimpanan di Peramban

Peramban modern menyediakan beberapa tempat penyimpanan data dengan karakteristik, masa hidup, dan tingkat keamanan yang berbeda. Perhatikan perbandingan berikut sebelum memutuskan tempat menyimpan data:

MekanismeKapasitas UmumMasa Hidup DataApakah Otomatis Dikirim ke Server di Setiap Request HTTP?Kasus Penggunaan Terbaik
localStorage~5 MB per originPermanen hingga dihapus oleh skrip atau pengguna.Tidak (murni di sisi klien).Preferensi tema (gelap/terang), progres modul belajar, penanda (bookmark), draf formulir.
sessionStorage~5 MB per originHanya selama satu tab terbuka (hilang saat tab ditutup).Tidak (murni di sisi klien).State langkah formulir multi-tahap (wizard) atau posisi filter sementara di tab tersebut.
IndexedDBRatusan MB hingga GB (sesuai ruang diska)Permanen hingga dihapus.Tidak (asinkron, mendukung transaksi & indeks).Aplikasi offline-first, menyimpan ribuan objek terstruktur, atau berkas biner (Blob/File).
HTTP Cookie (HttpOnly)~4 KBSesuai Max-Age / Expires.Ya, selalu dikirim otomatis melalui header Cookie.Identitas sesi autentikasi (session_id) yang wajib dilindungi dari JavaScript!
🚫 Aturan Keamanan Mutlak: Jangan Menyimpan Token Rahasia / Sesi Login Sensitif di localStorage!

Semua data di dalam localStorage dan sessionStorage dapat dibaca secara bebas oleh setiap baris JavaScript yang berjalan di halaman tersebut. Jika situs Anda mengalami satu saja celah XSS (atau memuat skrip pihak ketiga yang disusupi), penyerang cukup memanggil localStorage.getItem("token") untuk mencuri akun pengguna! Untuk sesi login produksi, gunakan Cookie dengan atribut HttpOnly, Secure, dan SameSite yang diatur oleh server.

1. Menggunakan localStorage dan sessionStorage dengan Aman

Kunci dan nilai yang disimpan di dalam localStorage maupun sessionStorage selalu bertipe string. Jika Anda langsung menyimpan objek localStorage.setItem("profil", { nama: "Adi" }), nilainya akan rusak menjadi string "[object Object]"!

Oleh karena itu, selalu gunakan JSON.stringify() saat menyimpan objek/array, dan JSON.parse() saat membacanya kembali—serta selalu bungkus di dalam try...catch!

Mengapa localStorage Wajib Dibungkus try...catch?

  1. setItem() dapat melempar QuotaExceededError: Ketika penyimpanan penuh atau pada mode penyamaran (private browsing) tertentu yang membatasi kuota.
  2. Pengguna dapat memblokir data situs: Memanggil localStorage saat pengaturan privasi peramban memblokir penyimpanan lokal dapat melempar SecurityError.
  3. JSON.parse() dapat melempar SyntaxError: Jika data di penyimpanan lokal termodifikasi atau rusak.
// Pembungkus penyimpanan lokal yang aman dan siap pakai di produksi
export const penyimpananLokal = {
  ambil(kunci, nilaiBawaan = null) {
    try {
      const teksMentah = window.localStorage.getItem(kunci);
      if (teksMentah === null) return nilaiBawaan;
      return JSON.parse(teksMentah);
    } catch (galat) {
      console.warn(`Gagal membaca kunci '${kunci}' dari localStorage:`, galat);
      return nilaiBawaan;
    }
  },

  simpan(kunci, nilai) {
    try {
      const teksJson = JSON.stringify(nilai);
      window.localStorage.setItem(kunci, teksJson);
      return true;
    } catch (galat) {
      console.warn(`Gagal menyimpan kunci '${kunci}' ke localStorage:`, galat);
      return false;
    }
  },

  hapus(kunci) {
    try {
      window.localStorage.removeItem(kunci);
    } catch (galat) {
      console.warn(`Gagal menghapus kunci '${kunci}':`, galat);
    }
  }
};

(Catatan: Pola inilah yang dipakai oleh Kodeloka sendiri untuk menyimpan progres modul, penanda, dan catatan belajar Anda di peramban!)

2. Menyinkronkan State Antar-Tab secara Real-Time dengan Event storage

Bagaimana jika pengguna membuka situs Kodeloka di Tab A dan Tab B secara bersamaan, lalu di Tab A ia mengganti tema menjadi Mode Gelap atau menyelesaikan Modul 5?

Ketika localStorage diubah di Tab A, peramban secara otomatis menembakkan event "storage" pada objek window di **semua tab lain (Tab B, Tab C) yang membuka domain (origin) yang sama**:

window.addEventListener("storage", (event) => {
  // event.key      -> Nama kunci yang berubah (mis. "kodeloka:tema")
  // event.oldValue -> Nilai string lama sebelum berubah
  // event.newValue -> Nilai string baru setelah berubah
  if (event.key === "kodeloka:tema" && event.newValue) {
    const temaBaru = JSON.parse(event.newValue);
    document.documentElement.setAttribute("data-tema", temaBaru);
  }
});

3. Pengantar IndexedDB untuk Data Berukuran Besar dan Asinkron

Karena localStorage bersifat sinkron (memblokir utas utama saat membaca/menulis string besar) dan dibatasi sekitar 5 MB, jangan gunakan localStorage untuk menyimpan ribuan baris katalog atau dokumen panjang.

Untuk kebutuhan tersebut, gunakan IndexedDB—basis data NoSQL transaksional bawaan peramban yang bekerja secara asinkron:

// Membuka koneksi IndexedDB dan membungkusnya dengan Promise modern
function bukaDatabaseCatatan() {
  return new Promise((resolve, reject) => {
    const permintaan = window.indexedDB.open("KodelokaDB", 1);

    // Dijalankan saat basis data pertama kali dibuat atau versinya dinaikkan
    permintaan.onupgradeneeded = (event) => {
      const db = event.target.result;
      if (!db.objectStoreNames.contains("catatan_modul")) {
        db.createObjectStore("catatan_modul", { keyPath: "idModul" });
      }
    };

    permintaan.onsuccess = () => resolve(permintaan.result);
    permintaan.onerror = () => reject(permintaan.error);
  });
}

Latihan Praktik: Menyimpan Draf Catatan Otomatis (Auto-Save) dan Sinkronisasi Antar-Tab

Buatlah berkas penyimpanan-catatan.html dan penyimpanan.js:

  1. Sediakan sebuah <textarea id="editor-catatan"> dan indikator status <output id="status-simpan">.
  2. Setiap kali pengguna mengetik (event "input"), simpan isi catatan beserta waktu pembaruannya ke localStorage menggunakan pembungkus try...catch yang aman.
  3. Saat halaman dimuat ulang, pulihkan kembali isi <textarea> dari localStorage.
  4. Tambahkan pendengar window.addEventListener("storage", ...) agar ketika halaman dibuka di dua tab berdampingan, ketikan di Tab 1 langsung muncul di Tab 2!