Setiap kali halaman dimuat ulang, seluruh variabel JavaScript kembali kosong, padahal banyak aplikasi butuh data yang bertahan lebih lama, misalnya tema pilihan atau draf catatan yang belum terkirim. Web Storage menyediakan penyimpanan pasangan kunci-nilai di dalam browser melalui dua object yang saling melengkapi. localStorage menyimpan data yang bertahan tanpa batas waktu, sedangkan sessionStorage menampung data yang hanya hidup selama satu sesi tab. Topik ini membahas keduanya, aturan mainnya, serta cara menyimpan object lewat JSON.
localStorage dan sessionStorage#
Keduanya memakai API yang identik, setItem(), getItem(), removeItem(), dan clear(), sehingga yang membedakan hanya masa simpannya. Data pada localStorage tetap ada meskipun tab ditutup dan komputer dimatikan, sedangkan data pada sessionStorage hilang begitu tabnya ditutup. Data juga tidak saling bocor antarsitus, karena penyimpanan dipisahkan per origin, yaitu kombinasi protokol, domain, dan port halaman yang sedang berjalan.
| Aspek | localStorage | sessionStorage |
|---|---|---|
| Masa simpan | bertahan sampai dihapus | hilang saat tab ditutup |
| Jangkauan baca | semua tab satu origin | tab yang sama saja |
| Contoh pemakaian | tema, preferensi tampilan | draf form pada satu tab |
Pemilihan antar keduanya mengikuti umur data yang disimpan. Preferensi yang sebaiknya diingat di kunjungan berikutnya masuk localStorage, sedangkan kerja sementara yang hanya relevan pada satu tab masuk sessionStorage. Kapasitas keduanya terbatas, umumnya sekitar lima megabita per origin, sehingga cukup untuk teks dan pengaturan tetapi bukan untuk berkas gambar.
Perubahan pada localStorage juga bisa dipantau lintas tab lewat event storage. Tab yang menyimpan data memicu event tersebut pada tab lain satu origin, dan handlernya dapat membaca event.key beserta nilai barunya. Pola ini berguna untuk hal-hal seperti menyamakan tema pada banyak tab yang terbuka, karena tab yang lain ikut tahu ketika preferensinya berganti.
Kunci, nilai, dan JSON#
Seluruh nilai yang disimpan diperlakukan sebagai string. Angka dan boolean otomatis diubah menjadi teks saat disimpan, sedangkan object dan array berubah menjadi tulisan "[object Object]" yang tidak berguna. Untuk data berstruktur, nilai dikemas dengan JSON.stringify() sebelum disimpan dan dibongkar dengan JSON.parse() setelah dibaca.
// tidak-dijalankan
const preferensi = { tema: "gelap", ukuranHuruf: 14 };
localStorage.setItem("preferensi", JSON.stringify(preferensi));
const terbaca = JSON.parse(localStorage.getItem("preferensi"));
console.log(terbaca.ukuranHuruf); // 14
Kuncinya juga bebas diberi nama, dan konvensi yang lazim memakai awalan aplikasi seperti "catatan-draf" agar tidak bertabrakan dengan kunci aplikasi lain pada origin yang sama. Melepas satu kunci memakai removeItem(), sedangkan clear() mengosongkan seluruh penyimpanan origin tersebut, jadi metode kedua perlu dipakai dengan hati-hati pada aplikasi yang berbagi origin.
Membaca dengan aman saat halaman dibuka#
getItem() mengembalikan null bila kuncinya belum pernah disimpan, dan nilai null ini menjadi tanda alami untuk memuat nilai bawaan. Pemeriksaannya dilakukan setiap halaman dibuka, sebab halaman tidak pernah tahu apakah kunjungan sebelumnya sempat menyimpan sesuatu. Selain itu, lingkungan seperti mode privat dapat memblokir penyimpanan, sehingga aksesnya dibungkus try/catch agar halaman tetap berjalan.
Ketersediaan penyimpanan juga dapat dideteksi lebih dahulu alih-alih menunggu error muncul. Pola yang lazim menguji localStorage dengan mencoba menulis dan membaca satu kunci percobaan di dalam try/catch, lalu menandai aplikasi untuk beralih ke mode tanpa penyimpanan bila ujiannya gagal. Dengan tanda itu, tombol simpan dapat disembunyikan dan pesan penggantinya ditampilkan sejak awal, tanpa kejutan di tengah pemakaian.
// tidak-dijalankan
let draf;
try {
draf = localStorage.getItem("catatan-draf");
} catch (error) {
draf = null; // penyimpanan tidak tersedia di lingkungan ini
}
if (draf !== null) {
console.log("Draf dimuat, panjang " + draf.length + " karakter");
} else {
console.log("Belum ada draf tersimpan");
}Demo berikut menyimpan satu textarea catatan ke localStorage ketika tombol Simpan ditekan, lalu memuatnya kembali setiap halaman dibuka. Tombol Hapus melepas kuncinya dengan removeItem(). Tekan Simpan, muat ulang halaman, dan catatannya akan tampil kembali beserta panjang karakternya. Bila lingkungan yang dipakai memblokir penyimpanan, panel keterangan menampilkan pesan penggantinya alih-alih membiarkan halaman error. Sebagai latihan lanjutan, ganti nama object penyimpanannya ke sessionStorage dan rasakan draf yang hilang bersama tabnya.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Demo localStorage untuk draf catatan</title>
<style>
body { font-family: "Segoe UI", Arial, sans-serif; margin: 14px; font-size: 14px; color: #1f2937; }
label { display: block; font-weight: 600; margin-bottom: 6px; }
textarea { width: 340px; max-width: 100%; height: 90px; padding: 8px; font: 14px "Segoe UI", Arial, sans-serif; }
button { padding: 6px 12px; margin: 10px 8px 0 0; cursor: pointer; }
#info { margin-top: 12px; padding: 10px; background: #eef2ff; border: 1px solid #4338ca; border-radius: 8px; min-height: 20px; max-width: 380px; }
</style>
</head>
<body>
<label for="catatan">Catatan</label>
<textarea id="catatan" placeholder="Tulis catatan di sini"></textarea>
<br>
<button id="simpan" type="button">Simpan catatan</button>
<button id="hapus" type="button">Hapus catatan</button>
<div id="info"></div>
<script src="index.js"></script>
<script>
// Demo Web Storage: draf catatan tersimpan di localStorage dan dimuat kembali.
const area = document.querySelector("#catatan");
const info = document.querySelector("#info");
const KUNCI = "catatan-demo";
function muat() {
try {
const tersimpan = localStorage.getItem(KUNCI);
if (tersimpan !== null) {
area.value = tersimpan;
info.textContent = "Catatan dimuat dari localStorage, panjang " + tersimpan.length + " karakter.";
} else {
info.textContent = "Belum ada catatan tersimpan.";
}
} catch (error) {
info.textContent = "Penyimpanan tidak tersedia di lingkungan ini.";
}
}
document.querySelector("#simpan").addEventListener("click", () => {
try {
localStorage.setItem(KUNCI, area.value);
info.textContent = "Catatan tersimpan, panjang " + area.value.length + " karakter.";
} catch (error) {
info.textContent = "Penyimpanan tidak tersedia di lingkungan ini.";
}
});
document.querySelector("#hapus").addEventListener("click", () => {
try {
localStorage.removeItem(KUNCI);
info.textContent = "Kunci \"" + KUNCI + "\" dihapus dari localStorage.";
} catch (error) {
info.textContent = "Penyimpanan tidak tersedia di lingkungan ini.";
}
});
muat();
</script>
<script>
// Demo Web Storage: draf catatan tersimpan di localStorage dan dimuat kembali.
const area = document.querySelector("#catatan");
const info = document.querySelector("#info");
const KUNCI = "catatan-demo";
function muat() {
try {
const tersimpan = localStorage.getItem(KUNCI);
if (tersimpan !== null) {
area.value = tersimpan;
info.textContent = "Catatan dimuat dari localStorage, panjang " + tersimpan.length + " karakter.";
} else {
info.textContent = "Belum ada catatan tersimpan.";
}
} catch (error) {
info.textContent = "Penyimpanan tidak tersedia di lingkungan ini.";
}
}
document.querySelector("#simpan").addEventListener("click", () => {
try {
localStorage.setItem(KUNCI, area.value);
info.textContent = "Catatan tersimpan, panjang " + area.value.length + " karakter.";
} catch (error) {
info.textContent = "Penyimpanan tidak tersedia di lingkungan ini.";
}
});
document.querySelector("#hapus").addEventListener("click", () => {
try {
localStorage.removeItem(KUNCI);
info.textContent = "Kunci \"" + KUNCI + "\" dihapus dari localStorage.";
} catch (error) {
info.textContent = "Penyimpanan tidak tersedia di lingkungan ini.";
}
});
muat();
</script></body>
</html>Kesalahan umum#
- Menyimpan object tanpa JSON.stringify. Object yang dipasang langsung menjadi string
"[object Object]", dan isinya tidak dapat dikembalikan. Bungkus nilainya denganJSON.stringify()sebelumsetItem(), lalu bongkar denganJSON.parse()setiap kali dibaca. - Mengira nilai yang dibaca tetap bertipe aslinya. Semua yang keluar dari
getItem()adalah string, sehingga angka 14 kembali sebagai"14"dan perbandingan ketat dengan angka gagal. Konversikan atau parsing kembali nilainya sebelum dipakai. - Bersandar pada Web Storage untuk data besar. Kapasitasnya terbatas sekitar lima megabita dan seluruh isinya berupa string, sehingga arsip yang besar dan berstruktur lebih cocok dititipkan ke IndexedDB pada topik berikutnya.
Ringkasan#
- Web Storage menyimpan pasangan kunci-nilai berupa string, dengan
localStorageyang bertahan tanpa batas waktu dansessionStorageyang hilang bersama tabnya. - Keduanya dipisah per origin dan memakai API yang sama, yaitu
setItem,getItem,removeItem, danclear. - Object dan array dikemas dengan
JSON.stringify()sebelum disimpan serta dibongkar denganJSON.parse()setelah dibaca. getItem()mengembalikannulluntuk kunci yang belum ada, sehingga pemuatan awal selalu disertai pemeriksaannulldan pengamanantry/catch.
Referensi#
- Window: localStorage — MDN
— dokumentasi
localStoragebeserta batas kapasitasnya. - Window: sessionStorage — MDN — masa simpan sessionStorage yang terikat pada tab.
- Using the Web Storage API — MDN — panduan pemakaian dan pemeriksaan ketersediaan penyimpanan.