Previously prefs.set broadcast many messages per each changed pref value to all open tabs, background page, popups. This lead to repeated and needless updates of various things like the toolbar icon, reapplying of styles, and whatnot. It could easily take more than 100ms on an average computer with many tabs open.
Now we debounce the broadcast & sync.set and coalesce all values in one object which is then sent just once per destination.
uBlock-extra rewrites html of some sites known to have bad scripts. Such new documentElement doesn't have our styles so we need to detect this case by observing the parent document node non-recursively, meaning we don't add overhead to the normal browsing experience.
Previously we incorrectly assumed that each sub-element is present in addedNodes array, but actually we need to inspect each added node's children e.g. using the superfast getElementsByTagName.
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
The injection code also runs outside of onInstalled event so we check first if a content script belonging to our execution context "generation" is already injected. This can happen on browser startup: the background page is loaded in several seconds after the normal web page tabs are loaded with our content script(s) already injected. The check itself is simply a "ping" message to each tab that should return true if the content script is alive and kicking.