简体   繁体   中英

Chrome Extension Background Page and Content Script Synchronization

Suppose I have the following code in my background page of a Chrome extension.

var opts;
chrome.storage.local.get(options, function(result) {
    opts = result[options];
});

chrome.runtime.onMessage.addListener(function(request, sender, response) {
    if (request.message === 'getOpts')
        response(opts);
});

In my content script, I access opts with message passing.

chrome.runtime.sendMessage({'message': 'getOpts'}, function(response) {
    console.log(opts);
});

Is there any guarantee that opts will be defined prior to a content script running? For example, when starting up the browser, the background page will run, and presumably the callback to chrome.storage.local.get will be added to the background page's message queue. Will Chrome finish processing that queue before injecting content scripts?

I could call chrome.storage.local.get from the content script, but my question is more generic, as I have additional async processing in my background page. At the moment, my content script checks with the background page to make sure everything is ready (using an interval to keep checking), but I am not sure whether such checks are necessary.

You can actually answer asynchronously to a message.

chrome.runtime.onMessage.addListener(function(request, sender, response) {
  if (request.message === 'getOpts') {
    chrome.storage.local.get('options', function(result) {
      response(result[options]);
    });
    return true; // Indicate that response() will be called asynchronously
  }
});

In case of chrome.storage this is, indeed, stupid as the API was specifically designed to addess the roundabout nature of using localStorage + Messaging in content scripts; you can query from content scripts directly.

But in general case of async processing, you can postpone answering to the message. You just need to return a true value from the listener to indicate that you're not done yet.

Do not rely on your variable being defined even if it is in your tests. In general, due to normal timing, your var should be set by the time it receives the message, but to be sure you should check so in your background onMessage. I've dealt with this by remembering in a global whether I've already initialized the extension and do so if needed from onMessage. The answer by xan shows how to use "return true" in that case to process the message once your async init finishes.

See an example of this on my chrome extension (search for bCalled )

There you can see I have a sendResponse method that takes care of detecting if the callback was already called and if not, return true (assumes an async operation is in progress and will call the callback later)

You can also experiment and test this by faking a delay in the background code that loads that var.

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