3

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

Community
  • 1
  • 1
FnuLnu
  • 85
  • 5

1 Answers1

3

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();
Xan
  • 74,770
  • 16
  • 179
  • 206
  • Thanks, this is definitely a good solution. Could you please suggest how to pass variable number parameters to the restoreGlobals to pass back to the callback (since different handlers need different number of call back variables). – FnuLnu Jul 14 '15 at 22:31
  • Um, why would you need to pass them through `restoreGlobals`? Closures will take care of it automatically - you can refer to `handler` parameters inside the callback. (edited it in) – Xan Jul 14 '15 at 22:33
  • Cool thanks! I am learning JS as well as chrome extension development at the same time. I was reading the "classic" closure discussion, calling setTimeout within a for loop to print the index. And incorrectly assumed, that I need to always pass the parameters along with the function call. Thanks for educating me about the closure rule. – FnuLnu Jul 14 '15 at 22:47
  • I highly recommend looking through answers to [this question](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work). – Xan Jul 14 '15 at 23:13