In my chrome extension, I have a background script that will fetch some data that it will need using a XMLHttpRequest
.
// note that this code is in the global scope i.e. outside of any function
// also note that I got this code from the page talking about XMLHttpRequest
var myData = [];
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange;
xhr.open("GET", "...", true);
xhr.send();
function handleStateChange() {
myData = Object.values(JSON.parse(xhr.responseText));
}
I want to know when will xor.send()
be run.
I observed that every time I reload the extension by pressing on the button, xhr.send()
will be called. I also observed that opening a new tab/window doesn't cause the background script to be run again.
I also found this page, that the background page gets "loaded" and "unloaded", but it says very little about when the code in the global scope of the background script is run.
Does it only run when the extension is installed/reloaded?
Background script can react to browser events and perform certain actions, the background page is loaded when it is needed, and unloaded when it goes idle. To use the background file, declare it as follows in the manifest.
This extension simply keeps Chrome running in the background, so that push notifications can be received while the browser is closed.
Events are browser triggers, such as navigating to a new page, removing a bookmark, or closing a tab. Extensions monitor these events in their background script, then react with specified instructions. A background page is loaded when it is needed, and unloaded when it goes idle.
Background Script - Provides persistence and handles background events. Content Script - Scripts that run in isolation in the context of the web page. Injected Script - Scripts that are programmatically injected into the web page.
Since only one copy of an extension's background page exists globally for all of your user's tabs and windows (responding to all per-tab resources), you will never see the start process (except during browser restarts and updates) if it is never being suspended. You can launch the task manager and see if the extension's background is always present and keeps the same Process ID
indicating it is not being shut down. There is also an optional Keepalive count
column, that shows how many activities are holding a process active, tasks with a -
may be being forced persistent, but –
seems to occur for multiple reasons.
If the background page has persistent:false
and meets all the other criteria to shut it down then it can be shutdown until the next event occurs (listener, getBackgroundPage()
, etc). The next event to require it would then load the background page executing the global scope, etc as part of setting up the listeners expected to be invoked.
You can go to chrome://extensions
enable developer mode and then inspect the extension's background page to view persistent
and permissions: [chrome.webRequest]
as they interfere:
If you still get persistent:true
behavior without explicit settings causing it, then it might be caused by state in your background page's global scope. It is best to still follow the migration guide, for example your xhr request belongs in a startup if you want to persist the data from first start beyond suspends:
chrome.runtime.onStartup.addListener(function() {
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = handleStateChange
xhr.open("GET", "...", true)
xhr.send()
function handleStateChange() {
chrome.storage.local.set({ myData:
JSON.stringify(Object.values(JSON.parse(xhr.responseText)))});
}
})
This should have roughly the equivalent behavior of running this code in the global scope with persistent:true
, but the xhr can be garbage collected as this is not a scope of other listeners etc. (Since chrome marks resource types like network sockets as reasons it can not suspend, it is important to get them out of scope.) After adapting, you can test behavior from the reloading the extension in the background page inspection even if the browser is still not suspending it automatically.
If you don't want to adapt to persistent:false
, then I would set persistent:true
in the manifest rather than rely on current implicit behavior. (Even if you are unable to cause a suspend on your test system, systems with more memory pressure or some other condition might unload your background pages if you set persistent:false
.)
If you find the Process ID
is changing, but you are having no problems then you are a little lucky. The system makes sure your global scope runs whenever it restarts the background page for you for an incoming request, but it does not make sure any asynchronous parts have completed. For example, it must start the ajax if it needs to start your background page to see if you have an appropriate listener, but it is allowed to call that listener when the synchronous portion of the global scope has finished running which may be before the response. Consequently, you can not count on MyData
if suspend is working correctly.
If you want to keep the xhr request in the global scope and correctly support persistent:false
, you would need to make sure listeners register immediately but internally wait on myData
. For example, if myData
was a Promise that handleStateChange()
resolves, other listeners can give asynchronous responses using myData.then(..)
and have an ajax response from the background page's most recent restart instead of stored in chrome local storage since ~installation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With