Many of you may have thought “Isn’t this what Service Workers are for?” after reading the headline. Yes, this proposal could be about Service Workers, but maybe not. On the Chrome team we’ve identified a set of problems that could be solved by Service Workers, but we feel that there are some downsides to that approach.
Anyways let me expand, here are some of the problems we would like to solve efficiently:
No easy way to control when to fetch and when to process the responses.
I often see people confused by the timing of sub-resources fetches and responses handling: “um, why is this image fetched before that stylesheet?” or “gush, why is this script executed before we do X?”. There are some known techniques (e.g. preload and then change rel=) to achieve some ordering, but they don’t always work as intended and even if they work it’s extremely hard to make sure the ordering when third-party libraries and frameworks are involved.
No easy way to rewrite multiple requests in a performant way.
A/B testing frameworks are apparently using hacks (e.g. open a textarea tag early-on) to rewrite everything in the document body, but this collides with UA’s preload scanner, which leads to suboptimal performance.
No easy way to bypass service workers for particular requests.
We’ve heard some demand for a way to skip service workers for requests that are always meant to go to the network, e.g. video streams. It was once discussed in Service Workers F2F and one of the resolution was to add service worker mode to Fetch request, but it’s still not possible to apply the mode for resource requests that come from HTML elements or third-party libraries. For those another option could be static routes, while its discussion is still up in the air.
As I wrote in the intro, any of the above be addressed by Service Workers, but there are some downsides or gaps:
Service Workers’ registration model and complex lifetime may not always be worth the trouble if the website owner just want to fiddle with a few sub resources.
Service Workers are “far” from the document(s), which makes it hard to coordinate the request/response ordering w.r.t. the page’s document state.
Service Workers can’t observe responses that are returned from caches that sit above Service Workers, e.g. Memory Cache or preload cache.
While Service Workers have fine control over the network, it doesn’t allow for fine control over the browser’s other most constrained resource: the main thread. Tasks will run unchecked and probably at the wrong time.
These made us wonder if it’s worth having a different, possibly simpler API from Service Workers. E.g. it can just be an inline script (e.g. <script type=”loading”>...</script>) in the page and just works for all the subresource loading after that. One could also imagine that certain HTML element provide hooks to provide the same level of control.
One more detail - will the preloader wait on kicking off resource requests until the inline request handler script is wired up? Are there any guarantees regarding how long that will take? Any estimates on potential regressions as a result of that?
I think a “lazyload” attribute is a much higher priority. People want resources delayed until after the page is done - right now there’s no way to do that in markup. If we had that, would many of the use cases your thinking of be solved?
I think the answer to all of those is “probably yes”.
There are a few differences with Service Worker as noted by Kinuko.
I’m particularly interested in these 3 differences:
Ability to act on “onEvaluate” events to control if/when/… work happen on the main thread, e.g. postpone evaluating the “async script in charge of comments at the end of an article” until the page reaches a meaningful above the fold state.
Ability for third party optimization services to provide or insert a snippet that would implement good default behaviors for known third parties.
For item 1, a SW could postpone a response in order to delay evaluation. But, operating on events coming from the main thread should provide greater control over the timing of tasks. In other words, if a SW postpone a non-essential response until the main document says “ATF ready”, there is no guarantee that the task associated with the response will run immediately, and the situation could change in the meantime.
Ideally, this type of “async script running at the wrong time” shouldn’t be a problem in the first place. But, for most websites out there, it’s hard if not impossible to do things in the ideal way (the third parties are added by a different team via a tag manager that they may not fully control). This would give the team that is tasked with crafting a good user experience, the ability to do so by having the final say. There are also some third parties who would love to have their render-blocking snippet come equipped with a user friendly timeout.
For item 2, convincing a customer to install a (service worker) script on their server is a lot harder and complex than asking them to copy paste a snippet.
For item 3, the devil is in the details but it seems quite appealing to give each player the ability to tweak their fetches and evaluation. Crazy idea: what if onfetch or onevaluation were attributes on certain HTML tags? Instead of shipping high level attributes such as timeout or lazyload, wouldn’t it be more aligned with the extensible web manifesto to start with a low level surface?