FnuLnu
FnuLnu

Reputation: 85

How to prevent/detect race condition between processing and restoring store data when waking up an Event page

I am using sendMessage and onMessage listener (both in background and content pages), and I am seeing some messages are getting lost. I have a few "global" variables that I store everytime I go to suspend state, and restore them among the first things when the script starts (I register the handlers first). However, given that the chrome.storage is asynchronous, I suspect message processing is happening before I get to load the global state (and hence the appearance of losing the messages).

Following is the relevant piece of code.

# Register some important listeners.
chrome.alarms.onAlarm.addListener(onAlarm);
chrome.runtime.onMessage.addListener(onMessage);

# Define global variables.
var tabIdList = new Array();
var keepAlives = new Array();
keepAlives["myTab1"] = -1;
keepAlives["myTab2"] = -1;
tabIdList["myTab1"] = -1;
tabIdList["myTab2"] = -1;

# Reload previously stored state of global variables...
reloadGlobalVariable();


# Handle received messages, anytime a message is received,
# set keepAlive for the tab that sends the message.
#
function onMessage(msg, sender) {
  if (sender.tab) {
    if (msg.message === "hello") {
        recordNewTab(msg.tabName, sender.tab.id);
    } 
  keepAlive(msg.tabName, sender.tab.id);
}

function recordNewTab(tabName, tabId) {
    tabIdList[tabName] = tabId;
}

function keepAlive(tabName, tabId) {
    if (tabIdList[tabName] == tabId) {
        keepAlives[tabName] = 1;
    }
}


chrome.runtime.onSuspend.addListener(function() {
    storeGlobalState();
});


function onAlarm(alarm) {
    for (var key in tabIdList) {
      if (tabIdList[key] != -1) {
        if (keepAlives[key] == -2) {
           removeTabRecord(key);
        } else {
          --keepAlives[key];
          sendMessage(key, "ping"); // content pages respond to this message
        }
      }
    }
  storeGlobalState(); // probably unnecessary.
}

How can I make sure that onAlarm only continues processing if the global variables have been reloaded?

I use chrome.storage.local.set/get which are asynchronous.

Original question to get debugging hints about suspended/wake states here...

How to debug background/event page suspended state

Upvotes: 3

Views: 370

Answers (1)

Xan
Xan

Reputation: 77551

Well, you can't do anything about async nature of Event page processing and Chrome Storage API. And there's no "delaying until" in async JS.

Therefore, you'll need to make do with callbacks. This should work:

var globalsReady = false;

chrome.foo.onBar.addListener(handler);

function handler(a, b, c) {
  restoreGlobals(function() {
    /* Do actual handling using a, b, c */
  });
  // Special note for onMessage: if you are sending a reply asynchronously,
  //  you'll need to return true; here
}

function restoreGlobals(callback) {
  if(!globalsReady) {
    chrome.storage.local.get(/*...*/, function(data) {
      /* restore globals here */
      globalsReady = true;
      if(typeof callback == "function") callback();
    });        
  } else {
    // Already done restoring
    if(typeof callback == "function") callback();
  }
}

restoreGlobals();

Upvotes: 3

Related Questions