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?
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?
Share Improve this question edited Nov 22, 2018 at 8:49 Raza Rafaideen 2,2511 gold badge21 silver badges30 bronze badges asked Nov 10, 2018 at 12:36 SweeperSweeper 278k23 gold badges242 silver badges397 bronze badges 5- You're talking about the event page ("persistent":false in manifest.json) and it'll run every time any of its listeners is triggered (like chrome.runtime.onMessage etc) and on the start of the browser profile as well as on manual reloading of the extension which replicates the same. – woxxom Commented Nov 10, 2018 at 13:15
- @wOxxOm When one of the listeners is triggered, do you mean the listener will be run, or the whole script (global scope) will be run? – Sweeper Commented Nov 10, 2018 at 13:17
- The whole page will run and then the listener will run. You can observe this easily via console.log. – woxxom Commented Nov 10, 2018 at 13:19
-
@wOxxOm I added a
console.log("xxx")
in the global scope. I reloaded the extension and saw that "xxx" is logged. However, when my listeners trigger, I only observe them being run, not "xxx" – Sweeper Commented Nov 10, 2018 at 13:54 - Well I guess you did something wrong then - like didn't actually wait for the page to unload - because no code runs in vacuum, it runs in the page context which is created by running the page script(s) as a whole. – woxxom Commented Nov 10, 2018 at 14:08
1 Answer
Reset to default 7 +50task manager pid and columns
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.
suspend never occurring
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
.)
suspend occurring but causing your code no problems
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 ining request, but it does not make sure any asynchronous parts have pleted. 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.
surfacing event handlers while still setting/using data in the global scope
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.