Fallback for when external script times out


#1

In bad network conditions, an external <script> may take a very long time to load (or not load at all). Is there a standard approach to provide a fallback to the user in this scenario?

If not, how about a <noscript> inside the <script> which would only be triggered if the browser “decides” that the external script load failed or took too long.


Linking to local (image) resources
#2

You could have an inline script that registers a timeout which is cancelled by an external script’s load event, and runs if the script haven’t loaded by the time the timeout expired. Then your inline script can perform the desired fallback behavior.

I suspect that having a built-in mechanism would hit some difficulties. In particular:

  • What happens when/if the script eventually loads?
  • What is the reasonable timeout that would fit most Web pages?

#3

If we are going the scripted route - service workers to monitor if the script loads would be a pretty good alternative to refire a fetch request for a different URL. Obviously a service worker won’t be there all the time however it would likely provide a route which was more robust if it was there (So using both techniques would be required I suspect).

I see the merits in the built in HTML route however I think this was a point of contention for the SRI spec which had a fallback route which was similar and was removed.


#4

Indeed, it would be nice to have a simple standard method to specify a fallback URL for a timed-out script, for example to load a local script if an external one’s load takes too long:

<script src="http://example.com/foobar.js" timeout="1" fallback="/js/foobar.js">

The timeout attribute in the example is a timeout in seconds after which the fallback URL should be retrieved instead of the one specified in the src attribute.

Moreover, this approach could probably apply to loading any resources (e.g. stylesheets and images), not just scripts.


#5

So as mentioned the SRI spec did have a fallback feature but was dropped through time implications and will be added back for v2+.

https://lists.w3.org/Archives/Public/public-webappsec/2014Dec/0045.html

It seems like the browser vendors were happy to implement this and it actually makes sense that this would be part of the Fetch specification rather than with SRI. @annevk any issue with this?


#6

I don’t think that we need to handle a fallback URL (if the second fails, why not a third one, etc).

However, I find the idea of fallback JS useful.

The immediate use-case I have in mind is to enable image lazy-loading (a la lazysizes ), with a decent fallback that displays the images when the script has failed to load.

Adding a timeout attribute that indicates an opt-in to this timeout behavior, as well as the actual time that the user should be left waiting for the script to arrive makes sense to me.

The main question that remains is “what would be the fallback?”. I think that in order for that to be a robust fallback (that covers more use-cases than the ones we can think of right now), the fallback should be defined as an inline script.

That inline script can be either:

  • The content of the <script> node.
  • An ontimeout based event handler.

That can be polyfilled using a ServiceWorker, or even simply by a timeout based script (if onload|onerror haven’t happened yet, remove the script and do something else instead).


#7

Why can’t the inline script handle the timeout mechanism as well?


#8

I guess it could. What do you have in mind?

We probably want to avoid a situation where legacy content like <script>//Code that currently doesn't run</script> will change behavior.


#9

Yeah I meant you would use a separate inline <script> that handles timeout and fallback. So no new browser features.


#10

Yeah, we could start with a prollyfill that does that, and see how usage goes.


#11

I don’t think that we need to handle a fallback URL (if the second fails, why not a third one, etc).

Because there are two things: external URL and local URL. External one could be temporarily unavailable. Local one is available if the local page it is loaded by is available.


#12

One of the main use cases here is similar to the sites that offer a fallback script if the code hasn’t loaded. So a fallback URL to a local copy fills these use cases:

  • SRI failure
  • CDN down
  • Opt in timeout behaviour
  • Fallback behaviour

However I get the point these might want to be separated with numerous fallbacks etc.