Refactor IndexedDB sync mechanism with dedicated store and improved handling

Co-authored-by: jxxghp <jxxghp@163.com>
This commit is contained in:
Cursor Agent
2025-07-07 14:32:55 +00:00
co-authored by jxxghp
parent 15340dd550
commit c5ab0a2cc6
+55 -36
View File
@@ -80,40 +80,67 @@ async function setStoredUnreadCount(count: number): Promise<void> {
// 简单的IndexedDB包装器 // 简单的IndexedDB包装器
async function openDB(): Promise<IDBDatabase> { async function openDB(): Promise<IDBDatabase> {
// Bump the version to add the new "sync" store while keeping existing data intact
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = indexedDB.open('mp_badge_db', 1) const request = indexedDB.open('mp_badge_db', 2)
request.onerror = () => reject(request.error) request.onerror = () => reject(request.error)
request.onsuccess = () => resolve(request.result) request.onsuccess = () => resolve(request.result)
request.onupgradeneeded = event => { request.onupgradeneeded = event => {
const db = (event.target as IDBOpenDBRequest).result const db = (event.target as IDBOpenDBRequest).result
// Badge store (existing)
if (!db.objectStoreNames.contains('badge')) { if (!db.objectStoreNames.contains('badge')) {
db.createObjectStore('badge') db.createObjectStore('badge')
} }
// Dedicated store for offline-sync items
if (!db.objectStoreNames.contains('sync')) {
db.createObjectStore('sync')
}
} }
}) })
} }
// 获取IndexedDB中的数据 // 获取IndexedDB中的数据
async function get(key: string): Promise<any> { async function get(key: string, storeName: string = 'badge'): Promise<any> {
const db = await openDB() const db = await openDB()
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transaction = db.transaction(['badge'], 'readonly') const tx = db.transaction([storeName], 'readonly')
const store = transaction.objectStore('badge') const store = tx.objectStore(storeName)
const request = store.get(key) const request = store.get(key)
request.onerror = () => reject(request.error) request.onerror = () => reject(request.error)
request.onsuccess = () => resolve(request.result) request.onsuccess = () => resolve(request.result)
}) })
} }
// 保存数据到IndexedDB // 保存数据到IndexedDB
async function set(key: string, value: any): Promise<void> { async function set(key: string, value: any, storeName: string = 'badge'): Promise<void> {
const db = await openDB() const db = await openDB()
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transaction = db.transaction(['badge'], 'readwrite') const tx = db.transaction([storeName], 'readwrite')
const store = transaction.objectStore('badge') const store = tx.objectStore(storeName)
const request = store.put(value, key)
request.onerror = () => reject(request.error) store.put(value, key)
request.onsuccess = () => resolve()
tx.oncomplete = () => resolve()
tx.onerror = () => reject(tx.error)
})
}
// 删除IndexedDB中的数据(确保事务完成)
async function del(key: string, storeName: string = 'badge'): Promise<void> {
const db = await openDB()
return new Promise((resolve, reject) => {
const tx = db.transaction([storeName], 'readwrite')
const store = tx.objectStore(storeName)
store.delete(key)
tx.oncomplete = () => resolve()
tx.onerror = () => reject(tx.error)
}) })
} }
@@ -363,7 +390,7 @@ const syncQueue: Array<{
// 添加请求到同步队列 // 添加请求到同步队列
async function addToSyncQueue(request: Request) { async function addToSyncQueue(request: Request) {
const id = `sync-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` const id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
const url = request.url const url = request.url
const method = request.method const method = request.method
@@ -384,8 +411,8 @@ async function addToSyncQueue(request: Request) {
timestamp: Date.now(), timestamp: Date.now(),
} }
// 保存到IndexedDB // 保存到IndexedDB (使用专用的 "sync" store)
await set(`sync-${id}`, syncItem) await set(id, syncItem, 'sync')
syncQueue.push(syncItem) syncQueue.push(syncItem)
// 注册后台同步 // 注册后台同步
@@ -397,23 +424,20 @@ async function addToSyncQueue(request: Request) {
// 执行同步队列中的请求 // 执行同步队列中的请求
async function processSyncQueue() { async function processSyncQueue() {
const db = await openDB() const db = await openDB()
const transaction = db.transaction(['badge'], 'readonly')
const store = transaction.objectStore('badge')
const request = store.getAllKeys()
const keys = await new Promise<IDBValidKey[]>((resolve, reject) => { // 使用专用的 "sync" store,并开启 readwrite 事务(便于后续删除)
request.onsuccess = () => resolve(request.result) const tx = db.transaction(['sync'], 'readwrite')
request.onerror = () => reject(request.error) const store = tx.objectStore('sync')
const items: Array<any> = await new Promise((resolve, reject) => {
const req = store.getAll()
req.onsuccess = () => resolve(req.result)
req.onerror = () => reject(req.error)
}) })
// 过滤出同步项 for (const syncItem of items) {
const syncKeys = keys.filter(key => String(key).startsWith('sync-')) const key = syncItem.id
for (const key of syncKeys) {
try { try {
const syncItem = await get(String(key))
if (!syncItem) continue
// 构建请求 // 构建请求
const init: RequestInit = { const init: RequestInit = {
method: syncItem.method, method: syncItem.method,
@@ -430,10 +454,8 @@ async function processSyncQueue() {
const response = await fetch(syncItem.url, init) const response = await fetch(syncItem.url, init)
if (response.ok) { if (response.ok) {
// 成功后删除同步项 // 成功后删除同步项,并等待事务完成
const deleteTransaction = db.transaction(['badge'], 'readwrite') await del(key, 'sync')
const deleteStore = deleteTransaction.objectStore('badge')
await deleteStore.delete(key)
// 通知客户端同步成功 // 通知客户端同步成功
const clients = await self.clients.matchAll() const clients = await self.clients.matchAll()
@@ -450,12 +472,9 @@ async function processSyncQueue() {
} catch (error) { } catch (error) {
console.error('Sync failed for item:', key, error) console.error('Sync failed for item:', key, error)
// 检查是否超过24小时,如果是则删除 // 如果该同步项已存在超过 24 小时,则将其丢弃
const syncItem = await get(String(key)) if (Date.now() - syncItem.timestamp > 24 * 60 * 60 * 1000) {
if (syncItem && Date.now() - syncItem.timestamp > 24 * 60 * 60 * 1000) { await del(key, 'sync')
const deleteTransaction = db.transaction(['badge'], 'readwrite')
const deleteStore = deleteTransaction.objectStore('badge')
await deleteStore.delete(key)
} }
} }
} }