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).
Related:
- https://developers.google.com/web/updates/2015/08/27/using-requestidlecallback
- https://w3c.github.io/requestidlecallback/
Use cases:
- Serialising the module store and writing to localStorage (MediaWiki core: mw.loader.store).
- Sending a batch of client-side statsd metrics to statsv (WikimediaEvents: statsv.js)
- Garbage collection for an application's old localStorage keys (CentralNotice: kvStore).
Proposal:
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).