The requestIdleCallback standard is settling and already implemented by Chrome. It fills a gap for a very real need. One that is impossible to emulate.
However we can do a best-effort approach. Either way, we don't want every product/team to implement their own way of doing this so let's at least standardise an interface for it (somewhat similar to MediaWiki's `DeferredUpdated::addUpdate()`, except completely different).
* Serialising the module store and writing to localStorage (mediawiki-core: mw.loader.store).
* Garbage collection for an application's old localStorage keys (CentralNotice: kvStore).
requestIdleCallback is impossible to polyfill due to the browser not exposing knowledge of internal queues for setTimeout, Promises resolution, event handlers etc. We can do a basic approach using setTimeout with a graceful period in-between each run and stop each iteration either when our own queue is empty, or if more than 50ms has past. (Since we can only measure the time after a task has run, perhaps limit at 40ms and run one more).
We'd implement a method (e.g. mw.requestIdleCallback) that will queue a task. When the queue is non-empty we'll periodically (e.g. every 4 seconds) run one or more tasks from the queue. (Though wait at least until after dom-ready and window-load).