Ephapox
Ephapox

Reputation: 827

Chrome Extension background page state

I am implementing a notification to be appended to a page if a user is not logged in on the extension but I only want the extension to do this once per browser session so that they don't get an annoying notification for every page they visit if they're not logged in.

They way I do this is by initializing a boolean in my background script to false, it represents whether or not a notification has been appended before.

Whenever a user is not logged in the background script will receive a message and based on the boolean mentioned above it will notify the user that they are not logged in.

background.js

var has_been_notified = false;
chrome.extension.onMessage.addListener(function(msg, sender) {
    if(!has_been_notified) {
        chrome.tabs.sendMessage(sender.tab.id, "login_notification");
        has_been_notified = true;
    }
})

The conditional should run once and never run again once the boolean is changed to true. This is under the assumption that the state of the background script is preserved throughout a browser session and never deployed again.

While I test the extension some random pages will get the notification even after the initial notification has fired. The pages that get it are about 1 in 10 but completely arbitrary of the site I visit.

Upvotes: 1

Views: 1733

Answers (1)

Xan
Xan

Reputation: 77571

Sounds like you're trying to use a "persistent": false Event page. This is the recommended approach, but it comes with the responsibility of understanding how it works.

Periodically, your background script will unload completely if it didn't do anything for a bit (on a scale of tenths of seconds). This loses the state of the JavaScript context, including all variables. Chrome remembers which events had listeners attached, and in case the event happens the page is loaded again, then the event is fired.

If you need to keep runtime state in memory throughout a browser session, use the storage API or IndexedDB. Since the event page does not stay loaded for long, you can no longer rely on global variables for runtime state.

So you'll need to save the state in chrome.storage.local:

// Don't use extension.sendMessage/onMessage, it's deprecated
chrome.runtime.onMessage.addListener(function(msg, sender) {
    chrome.storage.local.get(
        {has_been_notified: false}, // Providing a default if storage is empty
        function(data) {
            if(!data.has_been_notified) {
                chrome.tabs.sendMessage(sender.tab.id, "login_notification");
                chrome.storage.local.set({has_been_notified: true});
            }
        }
    );
});

If you need to reset this on each extension startup, hook into runtime.onStartup as opposed to execution of the script (which can restart repeatedly):

chrome.runtime.onStartup.addListener(function() {
    chrome.storage.local.set({has_been_notified: false});
});

Upvotes: 9

Related Questions