javascript - 如何在不覆盖其他写入操作的情况下将记录添加到 chrome.storage.local
问题描述
我正在创建一个 Chrome 扩展来测量某些类型的标签活动。因此,我通过 chrome.tabs 创建了各种事件侦听器,用于侦听 onReplaced、onUpdated、onCreated 和其他事件。
这些侦听器中的每一个都需要存储数据,我正在使用 Storage API (chrome.storage.local) 来做到这一点。然而,存储 API 是基于回调的,正如其规范中所定义的那样。
chrome.storage.local.get(key, myCallbackFunctionHere);
发生的情况是我在几乎同时触发的各种事件侦听器中对存储进行了多次调用。因此,您对存储 API 有两个不同get
的调用,然后set
调用存储一些数据。两组数据都需要存储,但它们会相互覆盖,最终只有一组数据被存储。
chrome.tabs.onCreated.addListener(onTabCreated);
chrome.tabs.onUpdated.addListener(onTabUpdated);
function onTabUpdated(tabId, changeInfo, tabAsUpdated) {
var someRelevantData = // extract some data to be stored
chrome.storage.sync.get({'myKey' : {}}, function (data) {
var myDictionaryUpdated = data.myKey;
myDictionaryUpdated ['newKey'] = someRelevantData;
chrome.storage.sync.set({'myKey' : myDictionaryUpdated }, function() {
console.log("myKey updated --- new value is &s", JSON.stringify(myDictionaryUpdated, null, 4));
});
});
}
function onTabActivated(activeInfo) {
var someDifferentAndEquallyImportantData = // extract some data to be stored
chrome.storage.sync.get({'myKey' : {}}, function (data) {
var myDictionaryUpdated = data.myKey;
myDictionaryUpdated['aSecondNewKey'] = someDifferentAndEquallyImportantData;
chrome.storage.sync.set({'myKey' : myDictionaryUpdated }, function() {
console.log("myKey updated --- new value is &s", JSON.stringify(myDictionaryUpdated , null, 4));
});
});
}
onTabUpdated 的回调返回使用“myKey”存储的对象,然后添加到它并在存储中更新它。但是,onTabActivated 也会在 'myKey' 处获取对象(它仍然是空的,因为来自上一个回调的 set 调用尚未运行),添加自己的数据,然后将更新的对象写入存储,覆盖任何数据包含在 onTabUpdated 回调中。
我在其他任何地方都找不到存储 API 的良好文档或答案 - Stack Overflow 上的相关问题不涉及多个事件侦听器在彼此之后立即调用存储 API。
解决方案
这是任何异步存储的标准问题,并非特定于扩展。
解决方案 1. 使用同步window.localStorage
. 它只能存储字符串,因此您需要 JSON.stringify 和 JSON.parse 来处理复杂数据。性能方面,假设数据小于几千字节,则没有区别,但如果有更多,则不要使用此方法。
解决方案 2. 使用等待上一次调用完成的互斥读/写函数:
const storage = (() => {
let mutex = Promise.resolve();
const API = chrome.storage.sync;
const mutexExec = (method, data) => {
mutex = Promise.resolve(mutex)
.then(() => method(data))
.then(result => {
mutex = null;
return result;
});
return mutex;
};
const syncGet = data => new Promise(resolve => API.get(data, resolve));
const syncSet = data => new Promise(resolve => API.set(data, resolve));
return {
read: data => mutexExec(syncGet, data),
write: data => mutexExec(syncSet, data),
};
})();
用法:
async function example() {
const {myKey} = await storage.read({myKey: {}});
myKey.foo = 'bar';
await storage.write({myKey});
}
解决方案 3:使用存储键值对的变量将缓存添加到以前的解决方案,但这是读者的练习(周围可能有现有的库/示例)。
推荐阅读
- javascript - type="module" javascript 文件是否都是相互隔离的?
- python - 将多个列字符串连接成一列
- ios - MacInCloud - Xcode 意外退出 (10.3)
- react-native - 如何防止 React Native FlatList 消费者由于状态数据增加而导致应用程序内存膨胀?
- notepad++ - 如何在记事本++中激活自动隐藏文件夹边距样式?
- scala - 如何在单独的文件中读取带有标题定义的 CSV 文件?
- c++ - 使用容器中元素的别名使用 std::list::remove 删除元素是否正确?
- html - 如何在包含的 div 之间设置空间?
- c++ - C++:私有类指针成员返回未定义的值
- rust - Err() 中不需要的撇号转义