简体   繁体   中英

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

I'm creating a Chrome extension that measures certain types of tab activity. As such, I have created various event listeners through chrome.tabs that listen to onReplaced, onUpdated, onCreated, and other events.

Each of these listeners needs to store data, and I'm using the Storage API (chrome.storage.local) to do that. However, the Storage API is based off of callbacks, as defined in their specs .

chrome.storage.local.get(key, myCallbackFunctionHere);

What happens is I have multiple calls to storage in various event listeners that may get triggered at almost the same time. So you have two different get calls to the storage API, which are followed by set calls to store some data. Both sets of data needs to be stored, but they overwrite each other and only one ends up getting stored.

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));
    });
  });
}

The callback for onTabUpdated returns the object stored with 'myKey', and then adds to it and updates it in storage. However, onTabActivated gets the object at 'myKey' as well (which is still empty, as the set call from the previous callback has not run yet), adds its own data, and then writes the updated object to storage, overwriting any data that was included in the onTabUpdated callback.

I can't find good documentation for the Storage API or answers anywhere else - related questions on Stack Overflow don't involve multiple event listeners making calls to the Storage API immediately after eachother.

This is a standard problem of any asynchronous storage, not specific to extensions.

Solution 1. Use the synchronous window.localStorage . It can only store strings though so you'll need JSON.stringify and JSON.parse for complex data. Performance-wise, assuming the data is less than a few kilobytes there'll be no difference, but if there's much more then don't use this method.

Solution 2. Use a mutexed read/write function that waits for the previous call to complete:

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),
  };
})();

Usage:

async function example() {
  const {myKey} = await storage.read({myKey: {}}); 
  myKey.foo = 'bar';
  await storage.write({myKey});
}

Solution 3: add caching to the previous solution using a variable that stores key-value pairs, but it's an exercise for the reader (there may be existing libraries/examples around).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM