正在同步 sync 和本地 chrome.storage

Synchronizing sync and local chrome.storage

我想知道如何在 Chrome 扩展中以正确的方式处理本地和同步存储。

这是我的案例:
我正在为一个特定站点开发扩展(目前),
其中包含一个内容脚本和一个弹出窗口。
弹出窗口包含用户可以进行更改的选项,然后将值发送到内容脚本以在页面上显示更改。

我希望尽可能减少保存和检索存储任务,最终它将保存在同步存储中,而不仅仅是本地。
同步存储有每分钟限制,而本地没有。

我知道如何使用长期连接监听来自内容脚本的弹出关闭调用并监听 onConnectonDisconnect,然后我可以执行保存任务,但是有没有更好的方法来保存对存储的读写呢?
我能想到的就是有一个后台脚本,我可以在其中存储变量中的更改,然后将它们来回发送到内容脚本和弹出窗口,所以这就像有一个存储而不实际使用存储,但是然后我如何检测用户何时离开特定域然后执行单个保存任务,以及 close/stop background/event 脚本?

chrome.storage.sync 持续操作的当前限制是每 2 秒 1 次(更准确地说是每小时 1800 次),突发速率限制为每分钟 120 次。

因此,您的工作是确保同步发生的频率不超过每 2 秒一次。

我会制作一个事件页面来处理 chrome.storage.onChanged 事件并同步这两个区域。 由于本地回声,令人惊讶这是一项艰巨的任务!

// event.js, goes into background.scripts in manifest

// Those will not persist if event page is unloaded
var timeout;
var queuedChanges = {};
var syncStamp = 1;

chrome.storage.onChanged.addListener(function(changes, area) {
  // Check if it's an echo of our changes
  if(changes._syncStamp && changes._syncStamp.newValue == syncStamp) {
    return;
  }

  if(area == "local") {
    // Change in local storage: queue a flush to sync

    // Reset timeout
    if(timeout) { clearTimeout(timeout); }

    // Merge changes with already queued ones
    for(var key in changes) {
      // Just overwrite old change; we don't care about last newValue
      queuedChanges[key] = changes[key];
    }

    // Schedule flush
    timeout = setTimeout(flushToSync, 3000);

  } else {
    // Change in sync storage: copy to local

    if(changes._syncStamp && changes._syncStamp.newValue) {
      // Ignore those changes when they echo as local
      syncStamp = changes._syncStamp.newValue;
    }
    commitChanges(changes, chrome.storage.local);
  }
});

function flushToSync() {
  // Be mindful of what gets synced: there are also size quotas
  // If needed, filter queuedChanges here

  // Generate a new sync stamp
  // With random instead of sequential, there's a really tiny chance
  //   changes will be ignored, but no chance of stamp overflow
  syncStamp = Math.random();
  queuedChanges._syncStamp = {newValue: syncStamp};

  // Process queue for committing
  commitChanges(queuedChanges, chrome.storage.sync);

  // Reset queue
  queuedChanges = {};
  timeout = undefined;
}

function commitChanges(changes, storage) {
  var setData = {};

  for(var key in changes) {
    setData[key] = changes[key].newValue;
  }

  storage.set(setData, function() {
    if(chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError.message);
    }
  });
}

这里的想法是在最后一次更改 local 后 3 秒同步。每个新更改都会添加到队列中并重置倒计时。虽然 Chrome 通常不遵守事件页面中的 DOM 计时器,但 3 秒足以在页面关闭之前完成。

另外请注意,从该代码更新区域将再次触发该事件。这是 considered a bug(与 window.onstorage 相比,不触发当前文档中的更改),但同时我添加了 _syncStamp 属性。它用于区分本地回声,尽管有微小的机会导致碰撞

您的其他代码(内容脚本)也应该依赖于 onChanged 事件而不是自定义 "okay, I changed a value!" 消息。