Safari内容脚本调用chrome.storage.local.set报错,求可行解决方案
Safari 扩展内容脚本存储配额问题的解决方案
问题核心
在部分Safari移动端设备/版本中,内容脚本调用await chrome.storage.local.set({ arr: [] })触发配额超限错误(即使本地存储为空),但扩展的非内容脚本页面可正常使用chrome.storage.local;同时Safari的Service Worker稳定性差,无法依赖其处理存储操作,需寻找内容脚本可直接使用的可靠替代方案。
最优方案:内容脚本直接使用IndexedDB存储
IndexedDB在Safari内容脚本中完全可用,且不存在chrome.storage.local的配额异常问题,是当前场景下的最优选择。以下是具体实现方案:
1. 封装IndexedDB操作工具类
为简化使用,封装通用的IndexedDB操作模块,覆盖初始化、设置、获取、删除数据的核心功能:
class ExtensionStorage { constructor(dbName = 'ExtensionDB', storeName = 'localStore') { this.dbName = dbName; this.storeName = storeName; this.db = null; } // 初始化数据库连接 async init() { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, 1); request.onupgradeneeded = (e) => { this.db = e.target.result; if (!this.db.objectStoreNames.contains(this.storeName)) { this.db.createObjectStore(this.storeName); } }; request.onsuccess = (e) => { this.db = e.target.result; resolve(); }; request.onerror = (e) => { reject(e.target.error); }; }); } // 存储数据 async set(key, value) { if (!this.db) await this.init(); return new Promise((resolve, reject) => { const transaction = this.db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); const request = store.put(value, key); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error); }); } // 获取数据 async get(key) { if (!this.db) await this.init(); return new Promise((resolve, reject) => { const transaction = this.db.transaction(this.storeName, 'readonly'); const store = transaction.objectStore(this.storeName); const request = store.get(key); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } // 删除数据 async delete(key) { if (!this.db) await this.init(); return new Promise((resolve, reject) => { const transaction = this.db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); const request = store.delete(key); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error); }); } }
2. 在内容脚本中替换原存储逻辑
用封装的工具类替代chrome.storage.local的调用:
// 初始化存储实例 const storage = new ExtensionStorage(); // 原chrome.storage.local.set替换为以下代码 try { await storage.set('arr', []); console.log('数据存储成功'); } catch (err) { console.error('存储失败:', err); } // 获取数据示例 const arr = await storage.get('arr'); console.log('获取到的数据:', arr);
方案优势
- 兼容性:Safari全平台(含移动端)内容脚本均支持IndexedDB,无配额异常问题;
- 稳定性:无需依赖Service Worker,规避了Safari中Service Worker被频繁回收的风险;
- 功能匹配:支持数组、对象等复杂数据类型存储,完全覆盖
chrome.storage.local的核心需求; - 性能达标:读写性能足以满足扩展常规存储场景的需求。
注意事项
- 首次使用需确保数据库初始化完成,封装类已通过
init方法自动处理; - 若存储大量结构化数据,可添加索引优化查询效率;
- 需捕获并处理存储操作的异常,避免影响内容脚本正常逻辑。
内容的提问来源于stack exchange,提问作者FMaz008
相关产品推荐
相关产品推荐

