-1

I run a web site remotely on remote clients as a display board. Sometimes when the internet is really bad, initial page load is never reached and the page gets stuck partially loaded (no CSS, dead images, etc)

Is there a way to force a refresh or at least call a function if the document doesn't load within a few minutes? A JavaScript function to handle this that loads as the very first thing and perhaps starts a timer and refreshes if document ready isn't reached in x seconds?

A Chrome extension is perhaps an option here.

  • 4
    Use `setTimeout()` to run a refresh function after a specified delay, and use `clearTimeout()` in the document ready to cancel the timeout. – nnnnnn Mar 19 '17 at 21:55
  • Doesn't sound like a good idea. What happens if the internet is *still* really bad? – Carol Skelly Mar 19 '17 at 22:05
  • Unless this is a duplicate question, I don't see any reason why you shouldn't post your comment as an answer, @nnnnnn. It's a handy technique and, given the good indexing provided by Google on [so] answers, it could help out quite a few people. – tao Mar 19 '17 at 22:07
  • @ZimSystem given a fair interval, this shouldn't be a problem. nnnnnn suggested canceling on document.ready, not on window.load. If used on window.load I agree it would be problematic, especially when used in conjunction with large assets/images. – tao Mar 19 '17 at 22:10
  • yeah, I meant the question/idea in general isn't a good idea.. @nnnnnn answer would work, but the problem is the page may continue to retry the refresh function. There's no guarantee that it will load any better on subsequent tries. – Carol Skelly Mar 19 '17 at 22:23
  • If the internet is still really bad? It's going to refresh and probably hit a network error. I'm thinking a chrome plugin might be a better option, since I have control over my client. – Mike Jenkins Mar 19 '17 at 22:43

1 Answers1

3

If the problem is really bad internet, refreshing the page is clearly not a good idea, because internet will still be bad when you refresh and chances are you'll just lose the few elements that have already loaded and you'll end up with a self-resetting, never-ending loop.

Let's break down what happens when a page loads:

  • <head> is read entirely, and no javascript is executed before CSSOM is built
  • CSSOM is built, after all CSS resources in it are read/loaded and parsed
  • <body> is added to DOM and, in parallel, the browser starts:
    • executing javascript, in order, starting with the scripts in <head> followed by the ones in <body> (if any)
    • reading/building DOM, queuing up all external resources for loading
  • if at any point a new CSS resource (<style> tag) is encoutered, DOM building stops, a new CSSOM is built, existing CSSOM is replaced with the new one, everything already added to DOM is repainted and DOM building is resumed
  • when DOM building reaches the end </body> tag, document.ready is fired
  • when all external resources have triggered .load, window.load is fired

Given the above, you have three major cases:

  • A. One or more .css resources in <head> fail to resolve. They neither load nor return an error, they just stall (due to server or network problems). This behavior prevents any javascript from executing.
  • B. CSSOM is built but for various reasons DOM building is interrupted/stalled (usually by javascript errors or loops, serious HTML validation errors (such as multiple/nested <body> tags, etc) resulting in DOM not being finished. This might prevent document.ready from firing, but all javascript read up to the error is executed, so you could place a timer and reset it on document.ready which could initiate a window.location.replace() if not fired in a specified time window - the solution proposed by @nnnnnn, in his comment.
  • C. All is well up to document.ready, but some external resources do not load (media files/scripts). The best approach here would be to just re-initiate loading for the ones that haven't loaded, without losing the ones that already did. This is a possible solution - untested.

From your question, I believe you're falling into the A case. The B would likely drop some errors in your console and would be easy to spot/fix.

For A i'm thinking of a possible hack, but it's dirty, at least at first glance. I'm thinking you should check which style-sheets usually stall loading and placing those at the beginning of <body> instead of inside <head>.
I know. This will automatically trigger a "No way!" reaction into any serious developers' mind, but let's see why it's not recommended. It's because you want to avoid FOUC at all costs.
And that's what normally happens when you place <style> tags in <body>. A new CSSOM is built, replacing the old one, existing content is repainted (causing FOUC) and DOM building is resumed. But if no content is placed before those <style> tags, nothing should be repainted and you benefit from javascript being executed before your problematic style-sheets are loaded.

How exactly you're going to load CSS resources into <body> should probably be subject of another question but here are a few possible methods:

  • <style>@import url();</style> - not sure if its valid and might not work cross-browser
  • adding <link> tags to <head> using javascript
  • after a bit of research, I found this article, documenting the following technique of making <link> tags in <head> no longer block rendering or javascript execution (yes, you no longer need to place them in <body> using this):
<link rel="stylesheet" href="css.css" 
      media="none" onload="if(media!='all')media='all'">

What technique you chose to make javascript start the timer before the CSS currently blocking your page finishes loading is not so important. The idea is to allow a script to assess what was loaded after a while and decide whether or not to reload the page or just re-initiate the loading process for unresolved resources.

You will still face FOUC and probably the best way around it would be to place opacity:0; on <body> until all CSS loaded and fade it in via javascript on window.load.


Regarding the reloading solution itself, you should probably use

location.replace(location.href);

...to avoid creating a new entry into your browser's history.

I hope you'll find some of the above helpful. Regards.

Community
  • 1
  • 1
tao
  • 82,996
  • 16
  • 114
  • 150
  • 1
    This answer is so informative, I'd like to see it added to SO Documentation with some citations. – A. Vidor Mar 20 '17 at 01:22
  • Thanks for that answer. It's nice to think outside of the box every now and then! My project definitely falls into category A, and that's the challenge. If I'm already dealing with partially loaded content, well, it difficult to say what will happen, and agreed it's so hard to test meaningfully. I was kind of hoping someone would come with an answer like "Duh, just use this Chrome extension" or an obscure meta-tag I didn't know about. What you propose is along the lines of what I thought would be possible. Thanks! – Mike Jenkins Mar 20 '17 at 02:01
  • Nice answer Andrei! – Carol Skelly Mar 20 '17 at 02:15
  • @MikeJenkins please accept this answer so others know the issue is resolved – Carol Skelly Mar 21 '17 at 02:18