Giới thiệu
Khi xây dựng các ứng dụng web, việc lưu trữ dữ liệu hiệu quả là rất cần thiết. JavaScript cung cấp hai tùy chọn lưu trữ dữ liệu phía khách hàng quan trọng: LocalStorage và IndexedDB. Bài viết này sẽ đề cập đến sự khác biệt, cách sử dụng, giới hạn và các thực tiễn tốt nhất khi làm việc với chúng.
1. LocalStorage là gì?
LocalStorage là một API lưu trữ đơn giản theo kiểu key-value cho phép lưu trữ một lượng nhỏ dữ liệu trong trình duyệt.
Tính năng:
- Lưu trữ dữ liệu dưới dạng chuỗi.
- Đồng bộ (có thể làm nghẽn giao diện người dùng).
- Giới hạn khoảng ~5MB cho mỗi nguồn gốc.
- Lưu trữ bền vững (dữ liệu vẫn còn sau khi làm mới trang hoặc khởi động lại trình duyệt).
- Không hỗ trợ lập chỉ mục hay truy vấn.
Trường hợp sử dụng:
- Lưu trữ dữ liệu nhỏ (ví dụ: sở thích người dùng, giao diện).
- Lưu trữ token xác thực (cần xem xét rủi ro bảo mật).
- Lưu trữ cài đặt cơ bản của ứng dụng.
Cách sử dụng LocalStorage
Đặt dữ liệu
javascript
localStorage.setItem("username", "JohnDoe");
Lấy dữ liệu
javascript
const user = localStorage.getItem("username");
console.log(user); // "JohnDoe"
Xóa dữ liệu
javascript
localStorage.removeItem("username");
Xóa tất cả dữ liệu
javascript
localStorage.clear();
2. IndexedDB là gì?
IndexedDB là một cơ sở dữ liệu NoSQL cấp thấp, không đồng bộ, dành cho việc lưu trữ một lượng lớn dữ liệu có cấu trúc.
Tính năng:
- Lưu trữ các đối tượng (không chỉ chuỗi).
- Không đồng bộ (các hoạt động không làm nghẽn).
- Dung lượng lưu trữ lớn hơn nhiều (có thể sử dụng lên đến 50% dung lượng đĩa).
- Hỗ trợ giao dịch và lập chỉ mục để truy vấn nhanh hơn.
- Lưu trữ bền vững (dữ liệu không bị xóa trừ khi người dùng/xuất chính sách trình duyệt).
Trường hợp sử dụng:
- Lưu trữ các tập dữ liệu lớn (ví dụ: danh mục sản phẩm, đồng bộ dữ liệu offline).
- Lưu trữ hình ảnh, tệp hoặc blobs.
- Lưu trữ phản hồi API một cách hiệu quả.
Cách sử dụng IndexedDB
Mở hoặc tạo cơ sở dữ liệu
javascript
const request = indexedDB.open("MyDatabase", 1);
request.onupgradeneeded = function(event) {
const db = event.target.result;
if (!db.objectStoreNames.contains("users")) {
db.createObjectStore("users", { keyPath: "id" });
}
};
Thêm dữ liệu
javascript
request.onsuccess = function(event) {
const db = event.target.result;
const txn = db.transaction("users", "readwrite");
const store = txn.objectStore("users");
store.add({ id: 1, name: "Alice", age: 25 });
txn.oncomplete = () => console.log("Dữ liệu đã được thêm!");
};
Đọc dữ liệu
javascript
request.onsuccess = function(event) {
const db = event.target.result;
const txn = db.transaction("users", "readonly");
const store = txn.objectStore("users");
const getRequest = store.get(1);
getRequest.onsuccess = () => console.log(getRequest.result);
};
Xóa dữ liệu
javascript
request.onsuccess = function(event) {
const db = event.target.result;
const txn = db.transaction("users", "readwrite");
const store = txn.objectStore("users");
store.delete(1);
txn.oncomplete = () => console.log("Dữ liệu đã bị xóa!");
};
3. So sánh LocalStorage và IndexedDB: Những khác biệt chính
| Tính năng | LocalStorage | IndexedDB |
|---|---|---|
| Kiểu dữ liệu | Chuỗi | Đối tượng (JSON, tệp, blobs) |
| Dung lượng | ~5MB | Lên đến 50% dung lượng đĩa |
| Hiệu suất | Đồng bộ (làm nghẽn UI) | Không đồng bộ (không làm nghẽn) |
| Hỗ trợ truy vấn | Không | Có (truy vấn lập chỉ mục) |
| Giao dịch | Không | Có (giao dịch ACID) |
| Bảo mật | Bị phơi bày với JavaScript (rủi ro XSS) | Bảo mật hơn (chạy trong sandbox) |
4. Giới hạn lưu trữ & Thực tiễn tốt nhất
Giới hạn lưu trữ
- LocalStorage: Giới hạn khoảng ~5MB cho mỗi nguồn gốc.
- IndexedDB: Có thể sử dụng gigabyte dung lượng, nhưng trình duyệt có thể nhắc nhở người dùng khi đạt dung lượng cao.
- Cảnh báo Safari: Safari có thể tự động xóa dữ liệu IndexedDB nếu dung lượng thấp.
Thực tiễn tốt nhất
- Sử dụng LocalStorage cho việc lưu trữ key-value nhỏ và đơn giản.
- Sử dụng IndexedDB cho dữ liệu phức tạp, tệp lớn hoặc chức năng offline.
- Nén dữ liệu (ví dụ:
JSON.stringify+ gzip cho LocalStorage). - Xử lý lỗi (ví dụ:
QuotaExceededErrortrong LocalStorage). - Sử dụng
navigator.storage.estimate()để kiểm tra dung lượng còn lại.
javascript
avigator.storage.estimate().then(({ quota, usage }) => {
console.log(`Đã sử dụng: ${usage} bytes`);
console.log(`Tổng dung lượng khả dụng: ${quota} bytes`);
});
5. Kết luận: Bạn nên sử dụng cái nào?
| Trường hợp sử dụng | Lưu trữ được khuyến nghị |
|---|---|
| Cài đặt nhỏ, giao diện | LocalStorage |
| Token xác thực người dùng | LocalStorage (ngắn hạn, với các cân nhắc về bảo mật) |
| Tập dữ liệu lớn (ví dụ: sản phẩm thương mại điện tử) | IndexedDB |
| Lưu trữ offline | IndexedDB |
| Hình ảnh, tệp, blobs | IndexedDB |
| Truy vấn nhanh, lập chỉ mục | IndexedDB |
Đối với hầu hết các ứng dụng web hiện đại, IndexedDB là lựa chọn tốt hơn nhờ khả năng mở rộng, hiệu suất và bảo mật. Tuy nhiên, LocalStorage vẫn hữu ích cho những nhu cầu lưu trữ nhanh và đơn giản.