使用 IndexedDB 緩存大量資料
起因是撰寫的油猴腳本使用localStorage存資料,到某一天發現資料怎麼存不進去了,排查才發現資料大於5MB了,然後就開始找有沒有其他更好的存資料方式,然後就發現了瀏覽器資料庫 API - IndexedDB。如果你正在開發需要在前端儲存大量資料的網頁應用程式,那麼這篇文章絕對不能錯過!
什麼是 IndexedDB?
IndexedDB 是一個低階的 API,用於在瀏覽器中儲存大量結構化資料。它允許你在使用者的瀏覽器中儲存幾乎無限量的資料,而且速度超快!與 localStorage 不同,IndexedDB 可以處理更複雜的資料結構,還支援索引搜尋,簡直是前端開發者的好朋友啊!
為什麼要學 IndexedDB?
- 儲存大量資料:相較於 localStorage 的 5MB 限制,IndexedDB 幾乎沒有儲存上限。
- 支援複雜資料結構:可以儲存和查詢 JavaScript 物件。
- 非同步操作:不會阻塞主執行緒,讓你的應用程式更流暢。
- 支援交易(Transactions):確保資料操作的一致性和可靠性。
IndexedDB 基本概念
在開始寫程式之前,我們先來了解一下 IndexedDB 的幾個重要概念:
- 資料庫(Database):就像一個大容器,裡面可以存放多個物件儲存區。
- 物件儲存區(Object Store):類似資料表,用來儲存資料。
- 索引(Index):用來加速搜尋特定欄位的值。
- 交易(Transaction):確保一系列操作全部成功或全部失敗。
- 游標(Cursor):用來遍歷資料集合的機制。
實作教學
好啦,廢話不多說,我們直接來寫程式吧!
1. 開啟資料庫連線
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| let db; const dbName = "MyAwesomeDB";
const request = indexedDB.open(dbName, 1);
request.onerror = function(event) { console.error("哎呀!開啟資料庫時發生錯誤:", event.target.error); };
request.onsuccess = function(event) { db = event.target.result; console.log("耶!成功連線到資料庫"); };
request.onupgradeneeded = function(event) { db = event.target.result; const objectStore = db.createObjectStore("users", { keyPath: "id" }); console.log("資料庫結構升級完成"); };
|
這段程式碼會開啟一個名為 "MyAwesomeDB" 的資料庫,版本為 1。如果資料庫不存在或版本需要升級,就會觸發 onupgradeneeded 事件,在這裡我們創建了一個名為 "users" 的物件儲存區。
2. 新增資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function addUser(user) { const transaction = db.transaction(["users"], "readwrite"); const objectStore = transaction.objectStore("users"); const request = objectStore.add(user); request.onerror = function(event) { console.error("新增資料失敗:", event.target.error); }; request.onsuccess = function(event) { console.log("讚啦!新增資料成功"); }; }
addUser({ id: 1, name: "小明", email: "xiaoming@example.com" });
|
3. 讀取資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function getUser(id) { const transaction = db.transaction(["users"]); const objectStore = transaction.objectStore("users"); const request = objectStore.get(id); request.onerror = function(event) { console.error("讀取資料失敗:", event.target.error); }; request.onsuccess = function(event) { if (request.result) { console.log("找到使用者:", request.result); } else { console.log("哎呀!找不到這個使用者"); } }; }
getUser(1);
|
4. 更新資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function updateUser(user) { const transaction = db.transaction(["users"], "readwrite"); const objectStore = transaction.objectStore("users"); const request = objectStore.put(user); request.onerror = function(event) { console.error("更新資料失敗:", event.target.error); }; request.onsuccess = function(event) { console.log("讚啦!更新資料成功"); }; }
updateUser({ id: 1, name: "小明", email: "xiaoming_new@example.com" });
|
5. 刪除資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function deleteUser(id) { const transaction = db.transaction(["users"], "readwrite"); const objectStore = transaction.objectStore("users"); const request = objectStore.delete(id); request.onerror = function(event) { console.error("刪除資料失敗:", event.target.error); }; request.onsuccess = function(event) { console.log("掰掰!刪除資料成功"); }; }
deleteUser(1);
|
進階技巧
1. 使用索引加速搜尋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| objectStore.createIndex("nameIndex", "name", { unique: false });
function getUserByName(name) { const transaction = db.transaction(["users"]); const objectStore = transaction.objectStore("users"); const index = objectStore.index("nameIndex"); const request = index.get(name); request.onsuccess = function(event) { if (request.result) { console.log("找到使用者:", request.result); } else { console.log("哎呀!找不到這個使用者"); } }; }
|
2. 使用游標遍歷資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function getAllUsers() { const users = []; const transaction = db.transaction(["users"]); const objectStore = transaction.objectStore("users"); const request = objectStore.openCursor(); request.onsuccess = function(event) { const cursor = event.target.result; if (cursor) { users.push(cursor.value); cursor.continue(); } else { console.log("所有使用者:", users); } }; }
|
注意事項
- 記得處理錯誤:IndexedDB 的操作可能會失敗,一定要好好處理錯誤狀況。
- 使用交易:盡可能將相關的操作放在同一個交易中,以確保資料一致性。
- 非同步思維:所有操作都是非同步的,要小心處理回調函式或使用 Promise。
- 版本控制:當需要修改資料庫結構時,要記得更新版本號碼。
結語
IndexedDB 雖然一開始看起來有點複雜,但是只要掌握了基本概念和用法,就能夠輕鬆地在前端儲存和管理大量資料,不過一般儲存使用localStorage還是夠用,畢竟我腳本是用了好幾年才到達5MB不得不換,資料少用localStorage還是很方便的,不過如果是持續增長的資料還是早換IndexedDB。