In short:
-
browser.storage
API is asynchronous and thus too slow. - You need fast values/overwrites if you want to override JS functions on websites. That’s the use case of my add-on.
Read the exact issue if you want to know what my exact problem is, but here is the abstract/generic way of what fails:
- I want a user-set value from browser.storage.sync in my content script. (This should be a fairly common use case.)
- Now you can actually use the
browser.storage
API in content scripts, which is great… - However that is slow! As it is asynchronous…
In my case, website JS run faster… - And I wanted to overwrite a JS function of the website…
- But while I am requesting my own setting to decide what I should do…
6…the website JS has already called the “non-faked” JS API, circumventing/ignoring my add-on.
So here we are: A typical race condition that results in a bug.
You may wonder, but you can get it faster…
I noticed you obviously keep the setting loaded in your background script and only load/inject it at tab load into your own script. (This injection has it’s own issues, but these are off-topic here.)
So I just try to inject the value as fast as I can (note I need to listen to tab creation events etc., so it is also not that fast…). In the end, it’s just one line of code to inject:
gettingFakedColorStatus.then((fakedColorStatus) => {
return browser.tabs.executeScript(tab.id, {
code: `
// apply setting value
fakedColorStatus = COLOR_STATUS["${fakedColorStatus.toUpperCase()}"]
applyWantedStyle(); // call to apply CSS
`,
allFrames: true,
runAt: "document_start" // run later, so we make sure COLOR_STATUS is already loaded
});
}
gettingFakedColorStatus
is an already resolved promise of storage.addons.sync
(or actually, a tiny wrapper of that API, but this does not matter here), so it is fast and does not actually wait. (it should run synchronously)
And, you may wonder, but it is actually faster than requesting the same value in the content script. In my case(testing with Firefox Nightly), it was around 20ms faster.
The problem is just: The original website’s JS that accesses the API I want to overwrite is again 20-70ms faster than even this method.
So I am too slow, again…
I have not even tried using any messaging you normally use between background script and content script. This will very likely be even slower…
What to do?
So what shall I do?
Why can’t I somehow start content scripts before a website even loads or so?
Or preload some data/JS there?
This thing totally results in race conditions, so is not there a way around it?