如何在不覆盖其他写入操作的情况下将记录添加到 chrome.storage.local

How to add records to chrome.storage.local without overriding other write operations

我正在创建一个 Chrome 扩展程序来测量某些类型的选项卡 activity。因此,我通过 chrome.tabs 创建了各种事件侦听器,用于侦听 onReplaced、onUpdated、onCreated 和其他事件。

这些侦听器中的每一个都需要存储数据,我正在使用存储 API (chrome.storage.local) 来做到这一点。但是,存储 API 是基于回调的,如他们的 specs.

中所定义
chrome.storage.local.get(key, myCallbackFunctionHere);

发生的情况是我在各种事件侦听器中多次调用存储,这些事件侦听器可能几乎同时被触发。因此,您有两个不同的 get 调用存储 API,然后是 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 的回调 returns 用 'myKey' 存储的对象,然后添加到它并在存储中更新它。但是,onTabActivated 也获取了 'myKey' 处的对象(它仍然是空的,因为之前回调的 set 调用还没有 运行 ),添加自己的数据,然后将更新后的对象写入存储,覆盖 onTabUpdated 回调中包含的任何数据。

我找不到存储的良好文档 API 或在其他任何地方找到答案 - Stack Overflow 上的相关问题不涉及多个事件侦听器在彼此之后立即调用存储 API .

这是任何异步存储的标准问题,不特定于扩展。

解决方案1.使用同步window.localStorage。它只能存储字符串,所以你需要 JSON.stringify 和 JSON.parse 来存储复杂的数据。性能方面,假设数据小于几千字节没有区别,但如果有更多则不要使用此方法。

解决方案 2. 使用互斥 read/write 函数等待上一个调用完成:

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:使用存储键值对的变量将缓存添加到先前的解决方案中,但这是 reader 的练习(周围可能存在 libraries/examples)。