Read more »
1. IndexedDB là gì và tại sao lại "siêu tốc"?
Thông thường, để làm một ứng dụng web có lưu trữ dữ liệu (như app quản lý chi tiêu, ghi chú, danh sách công việc), bạn cần thuê server và setup cơ sở dữ liệu (MySQL, MongoDB...). Việc này vừa tốn chi phí, vừa làm giảm tốc độ phản hồi do phải gửi request qua Internet.
IndexedDB là một hệ quản trị cơ sở dữ liệu phi quan hệ (NoSQL) được tích hợp ngay bên trong trình duyệt của người dùng.
Siêu tốc: Dữ liệu đọc/ghi trực tiếp từ ổ cứng máy tính/điện thoại của user nên tốc độ gần như bằng 0ms.
Offline First: Ứng dụng vẫn chạy và lưu dữ liệu bình thường ngay cả khi không có mạng.
Dung lượng lớn: Không bị giới hạn 5MB như
localStorage, IndexedDB có thể lưu hàng trăm MB đến hàng GB dữ liệu.
2. Thực hành: Xây dựng ứng dụng "Ghi chú siêu tốc"
Chúng ta sẽ tạo một file HTML duy nhất chứa cả giao diện (HTML/CSS) và logic xử lý dữ liệu (JavaScript + IndexedDB).
Bước 1: Tạo file index.html và dán đoạn code sau:
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ghi Chú Siêu Tốc (IndexedDB)</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f4f7f6;
max-width: 600px;
margin: 40px auto;
padding: 20px;
}
h2 { color: #333; text-align: center; }
.input-group {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
button {
padding: 10px 20px;
background-color: #28a745;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover { background-color: #218838; }
ul { list-style: none; padding: 0; }
li {
background: white;
padding: 12px;
margin-bottom: 8px;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.btn-delete {
background-color: #dc3545;
padding: 5px 10px;
font-size: 14px;
}
.btn-delete:hover { background-color: #c82333; }
</style>
</head>
<body>
<h2>📝 Ghi Chú Siêu Tốc</h2>
<div class="input-group">
<input type="text" id="noteInput" placeholder="Nhập ghi chú mới vào đây...">
<button onclick="addNote()">Thêm</button>
</div>
<ul id="noteList"></ul>
<script>
// --- LOIGC INDEXEDDB ---
let db;
const dbName = "NoteAppDB";
const storeName = "notes";
// 1. Khởi tạo và mở Database
const request = indexedDB.open(dbName, 1);
// Tạo cấu trúc bảng (Object Store) nếu là lần đầu tiên chạy app
request.onupgradeneeded = function(e) {
db = e.target.result;
if (!db.objectStoreNames.contains(storeName)) {
// Tạo bảng 'notes' với khóa chính tự tăng (id)
db.createObjectStore(storeName, { keyPath: "id", autoIncrement: true });
}
};
request.onsuccess = function(e) {
db = e.target.result;
console.log("Đã kết nối IndexedDB thành công!");
displayNotes(); // Tải dữ liệu cũ lên giao diện
};
request.onerror = function(e) {
console.error("Lỗi kết nối database:", e.target.error);
};
// 2. Hàm thêm dữ liệu (Create)
function addNote() {
const input = document.getElementById("noteInput");
const text = input.value.trim();
if (!text) return;
const transaction = db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const newNote = { text: text, createdAt: new Date() };
store.add(newNote);
transaction.oncomplete = function() {
input.value = ""; // Xóa rỗng ô input
displayNotes(); // Cập nhật lại danh sách hiển thị
};
}
// 3. Hàm đọc và hiển thị dữ liệu (Read)
function displayNotes() {
const list = document.getElementById("noteList");
list.innerHTML = ""; // Xóa danh sách cũ trên giao diện
const transaction = db.transaction([storeName], "readonly");
const store = transaction.objectStore(storeName);
const cursorRequest = store.openCursor(); // Dùng con trỏ để duyệt qua từng dòng dữ liệu
cursorRequest.onsuccess = function(e) {
const cursor = e.target.result;
if (cursor) {
const li = document.createElement("li");
li.innerHTML = `
<span>${cursor.value.text}</span>
<button class="btn-delete" onclick="deleteNote(${cursor.value.id})">Xóa</button>
`;
list.appendChild(li);
cursor.continue(); // Chuyển sang dòng tiếp theo
}
};
}
// 4. Hàm xóa dữ liệu (Delete)
function deleteNote(id) {
const transaction = db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
store.delete(id);
transaction.oncomplete = function() {
displayNotes(); // Cavy nhật lại giao diện sau khi xóa
};
}
</script>
</body>
</html>
Bước 2: Chạy và kiểm tra kết quả
Bạn chỉ cần click đúp vào file
index.htmlvừa lưu để mở nó bằng bất kỳ trình duyệt nào (Chrome, Edge, Safari...).Hãy thử gõ vài ghi chú rồi bấm Thêm.
Thử nghiệm độ "bá đạo" của IndexedDB: F5 (Reload) lại trang, hoặc tắt hẳn trình duyệt đi rồi mở lại. Bạn sẽ thấy dữ liệu của mình vẫn nằm nguyên ở đó.
Bạn có thể nhấn
F12trên bàn phím -> Chọn tab Application (hoặc Storage) -> Chọn IndexedDB ở cột bên trái để tận mắt nhìn thấy cơ sở dữ liệu đang nằm ngay trong trình duyệt của mình.
3. Kiến thức cốt lõi cần nhớ khi làm việc với IndexedDB
Mặc dù code mẫu phía trên rất ngắn gọn, nhưng để làm chủ IndexedDB bạn cần hiểu mô hình hoạt động của nó gồm 3 khái niệm:
Database (Cơ sở dữ liệu): Là nơi chứa toàn bộ ứng dụng của bạn. Bạn có thể tạo nhiều database cho các ứng dụng khác nhau.
Object Store (Kho chứa): Tương đương với "Bảng" (Table) trong SQL. Đây là nơi bạn lưu các đối tượng JavaScript (Object). Trong ví dụ trên, chúng ta dùng cơ chế tự tăng key (
autoIncrement: true).Transaction (Giao dịch): Mọi hành động Đọc (Readonly) hoặc Ghi (Readwrite) vào Database trong IndexedDB đều bắt buộc phải nằm trong một Transaction. Điều này đảm bảo an toàn dữ liệu: nếu một chuỗi hành động bị lỗi ở giữa chừng, toàn bộ quá trình sẽ được khôi phục (rollback) lại trạng thái cũ, không sợ bị lỗi hỏng file.



0 Reviews