Right now in mw.loader.work, before it considers fetching a batch of modules from the server, first:
- It iterates over the list and sees if there is an entry in the local cache for that module name and module version.
- It gathers all the results, tries to eval them (in one large globalEval call), and then removes those from the batch.
- Then, if anything is left, we'll continue doing any fetch(es) for them (which are asynchronous).
Right now step 1 and 2 happen synchronously, sometimes during page load. This is despite that fact that our one and only script-src is asynchronous. The load() command for our module list is inside a deferred script tag (<script>RLQ.push(function)). The execution of that function is managed by the script loaded via script-async-src. However in case of repeat visits, the conditions are usually true:
- The script-async-src is still non-blocking, but does execute very early on.
- The script will execute all RLQ inline scripts.
- It'll enqueue the module names.
- mw.loader.work will synchronously evaluate any needed scripts we have in local store.
- Then, and only then, does it create script-src tags for the other modules (which is just a simple createElement and appendChild, rest is asynchronous).
For repeat views, most modules are likely in the local store. This gets much worse after we implement T109837 (consolidating the "top" and "bottom" queues).