💓 博客主页:瑕疵的CSDN主页
📝 Gitee主页:瑕疵的gitee主页
⏩ 文章专栏:《热点资讯》
目录
在现代 Web 开发中,跨上下文(如多个标签页、Worker 线程或 Service Worker)的数据同步是一个常见的挑战。结合 Web Locks API 和 IndexedDB,可以有效解决这一问题,同时优化性能。本文将通过代码示例和实践场景,展示如何利用这两项技术实现高效、可靠的数据同步。
Web Locks API 提供了一种机制,允许开发者在多个上下文中协调对共享资源的访问。其核心功能包括:
- 加锁(Acquire Lock):确保同一时间只有一个上下文可以访问共享资源。
- 释放锁(Release Lock):在操作完成后释放锁,允许其他上下文继续访问。
- 队列管理:自动管理等待锁的上下文队列。
IndexedDB 是浏览器内置的 NoSQL 数据库,支持异步操作和事务管理。其特点包括:
- 大容量存储:支持数百 MB 到数 GB 的数据存储。
- 事务支持:通过 ACID 事务保证数据一致性。
- 索引查询:支持高效的索引和复合索引。
首先,创建一个 IndexedDB 数据库,并定义对象仓库(Object Store)和索引。
// utils/indexedDB.js
const DB_NAME = 'SyncDB';
const STORE_NAME = 'userPreferences';
const DB_VERSION = 1;
async function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
const store = db.createObjectStore(STORE_NAME, { keyPath: 'userId' });
store.createIndex('lastUpdated', 'lastUpdated', { unique: false });
}
};
request.onsuccess = (event) => {
const db = event.target.result;
resolve(db);
};
request.onerror = (event) => {
reject(event.target.error);
};
});
}
export { initDB };
通过 Web Locks API 确保多个上下文对 IndexedDB 的访问有序。
// services/dataSync.js
import { initDB } from './indexedDB';
const LOCK_NAME = 'sync-lock';
async function acquireLockAndWriteData(userId, preferences) {
await navigator.locks.request(LOCK_NAME, async (lock) => {
const db = await initDB();
const transaction = db.transaction(STORE_NAME, 'readwrite');
const store = transaction.objectStore(STORE_NAME);
preferences.userId = userId;
preferences.lastUpdated = new Date().toISOString();
await store.put(preferences);
db.close();
});
}
async function readDataWithLock(userId) {
let result = null;
await navigator.locks.request(LOCK_NAME, async (lock) => {
const db = await initDB();
const transaction = db.transaction(STORE_NAME, 'readonly');
const store = transaction.objectStore(STORE_NAME);
const request = store.get(userId);
request.onsuccess = (event) => {
result = event.target.result;
};
db.close();
});
return result;
}
在多个标签页中,通过 Web Locks API 协调对 IndexedDB 的访问。
// components/syncComponent.js
import { readDataWithLock, acquireLockAndWriteData } from '../services/dataSync';
class SyncComponent extends HTMLElement {
constructor() {
super();
this.userId = 'user123';
}
async updatePreferences() {
const preferences = {
theme: 'dark',
language: 'zh-CN',
};
await acquireLockAndWriteData(this.userId, preferences);
console.log('Preferences updated successfully.');
}
async fetchPreferences() {
const data = await readDataWithLock(this.userId);
console.log('Fetched preferences:', data);
}
}
customElements.define('sync-component', SyncComponent);
通过缓存减少对 IndexedDB 的频繁访问。
// utils/cache.js
const cache = new Map();
function getCache(key) {
return cache.get(key);
}
function setCache(key, value, ttl = 60000) {
cache.set(key, { value, expiresAt: Date.now() + ttl });
setTimeout(() => cache.delete(key), ttl);
}
在事务中批量执行操作,减少数据库交互次数。
async function batchWriteData(dataList) {
await navigator.locks.request(LOCK_NAME, async (lock) => {
const db = await initDB();
const transaction = db.transaction(STORE_NAME, 'readwrite');
const store = transaction.objectStore(STORE_NAME);
dataList.forEach((data) => {
data.lastUpdated = new Date().toISOString();
store.put(data);
});
db.close();
});
}
合理设计索引以加速查询。
// 修改数据库初始化逻辑
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
const store = db.createObjectStore(STORE_NAME, { keyPath: 'userId' });
store.createIndex('lastUpdated', 'lastUpdated', { unique: false });
store.createIndex('theme_language', ['theme', 'language'], { unique: false });
}
};
当用户在多个标签页中修改偏好设置时,通过 Web Locks API 确保数据一致性。
<sync-component></sync-component>
<script type="module" src="/components/syncComponent.js"></script>
在离线状态下缓存用户操作,待网络恢复后同步到服务器。
// services/offlineSync.js
async function syncOfflineData() {
const offlineData = getOfflineDataFromCache();
if (offlineData.length > 0) {
await batchWriteData(offlineData);
clearOfflineCache();
console.log('Offline data synced to IndexedDB.');
}
}
通过结合 Web Locks API 与 IndexedDB,可以显著提升跨上下文数据同步的性能。以下是优化前后的对比:
图1:优化前后性能对比
图2:Web Locks API 与 IndexedDB 协作流程
通过 Web Locks API 与 IndexedDB 的结合,开发者可以高效解决跨上下文数据同步的问题,并通过缓存、批量操作和索引优化进一步提升性能。未来,随着浏览器对 Web Locks API 的进一步支持,这种模式将在更多复杂场景中发挥重要作用。
提示:在实际开发中,建议结合
等封装库简化 IndexedDB 操作,并通过
监控性能指标,持续优化应用表现。