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.