Loser Loser - 1 month ago 24
Javascript Question

chrome...addListener, how to wait for chrome.storage.sync.get?

My extension is modifying some URLs. It worked fine, but now I want to check if modifying is enabled in the settings or not.

chrome.webRequest.onBeforeRequest.addListener
(
modifyUrl,
{urls: ['http://somewebsite/*'], types: ['main_frame']},
['blocking']
);


The problem is that I do not know how to wait for the value. I must get the setting before exiting
modifyUrl
. Is this possible? If this were C#, I would probably have used
ManualResetEvent
or something after calling the
sync.get
.

function modifyUrl(details)
{
chrome.storage.sync.get("someSetting",
function (data)
{
//I can get the setting here
}
);

//how to know the setting here?
if(enabled in the setting)
{
return {redirectUrl: some different url};
}
}

Answer

See Returning Chrome storage API value without function for detailed explanations.

In short, a blocking onBeforeRequest event is synchronous so it can't depend on asynchronous functions such as all chrome.* API callbacks to derive its return value.

Cache the data in a global variable, and use chrome.storage.onChanged to update it when changed elsewhere, which can easily happen if you use chrome.storage.sync (it's updated on profile sync).

var settingEnabled; // a global variable
chrome.storage.sync.get("someSetting", function (data) {
    var settingEnabled = data.someSetting;
});

chrome.webRequest.onBeforeRequest.addListener(
    modifyUrl,
    {urls: ['http://somewebsite/*'], types: ['main_frame']},
    ['blocking']
);

function modifyUrl(details) {
    if (settingEnabled) {
        return {redirectUrl: 'http://example.com'};
    }
}

chrome.storage.onChanged.addListener(function(changes, area) {
    if (area == "sync" && "someSetting" in changes) {
        settingEnabled = changes.someSetting.newValue;
    }
});

Of course, in case you want to disable processing completely, simply detach the listener:

function toggleListener(enable) {
    if (enable) {
        chrome.webRequest.onBeforeRequest.addListener(
            modifyUrl,
            {urls: ['http://somewebsite/*'], types: ['main_frame']},
            ['blocking']
        );
    } else {
        chrome.webRequest.onBeforeRequest.removeListener(modifyUrl);
    }
}

chrome.storage.onChanged.addListener(function(changes, area) {
    if (area == "sync" && "someSetting" in changes) {
        toggleListener(changes.someSetting.newValue);
    }
});

chrome.storage.sync.get("someSetting", function (data) {
    toggleListener(data.someSetting);
});

Another interesting approach is to re-attach onBeforeRequest inside storage.get callback on updates.