Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible actions before document is ready

Problem

I wrote a script for informing user that the page is loading slowly (say, it is because of slow internet connection). The script is put first in the <head></head> and is quite simple:

var GLOBAL_TIMEOUT = setInterval(function () {      
    alert("The Internet connection is slow. Please continue waiting.");
}, 30000);

//clear that interval somewhere else when document is ready
$(function () {
    clearInterval(GLOBAL_TIMEOUT);
});

Question

In the current example information is simply alerted. Is there any other possible way to inform user about slow loading of the page (particularly when some js or css file in the head is really big and takes some time to load)? I've tried manipulating the DOM (which is, in my opinion, is not right thing to do before document is ready) and document.body resulted in null.

Additional

The solution with setting an interval is from here. Any other ideas of how to do that are greatly appreciated.

like image 514
Artyom Neustroev Avatar asked Sep 06 '13 04:09

Artyom Neustroev


1 Answers

If it were me I'd probably try something like this:

<style>
.notification {
  font-family: sans-serif;
  font-size: 11pt;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  padding: 30px;
  text-align: center;
  background: #eee;
  -webkit-opacity: 0;
  -moz-opacity: 0;
  -ms-opacity: 0;
  -o-opacity: 0;
  opacity: 0;
  -webkit-transition: all 1s;
  -moz-transition: all 1s;
  -ms-transition: all 1s;
  -o-transition: all 1s;
  transition: all 1s;
}
.notification.reveal {
  -webkit-opacity: 1;
  -moz-opacity: 1;
  -ms-opacity: 1;
  -o-opacity: 1;
  opacity: 1;
}
</style>

With the following markup just after the <body>

<div id="note-wrap"></div>

And the following markup just before the </body>

<script>
  (function(){
    var gui = {}, tos = {};
    gui.wrap = document.getElementById('note-wrap');
    gui.note = document.createElement('div');
    gui.note.className = 'notification';
    gui.note.innerHTML = 
      'The page is taking a long time to download. ' + 
      'Please continue waiting.'
    ;
    /// run the setInterval at 30s
    tos.append = setInterval(function(){
      /// add the note element
      gui.wrap.appendChild(gui.note);
      /// trigger the css transitions
      tos.reveal = setTimeout(function(){
        gui.note.className = 'notification reveal'; delete tos.reveal;
      }, 100);
      tos.conceal = setTimeout(function(){
        gui.note.className = 'notification'; delete tos.concel;
      }, 5000);
    }, 30000);
    /// on dom ready clear timeouts
    jQuery(function(){
      clearInterval(tos.append);
      if ( tos.conceal && tos.reveal ) {
        clearTimeout(tos.reveal);
        clearTimeout(tos.conceal);
      }
    });
  })();
</script>

By placing this script just before the close body tag you can access all previously parsed DOM elements, you do not need to wait for DOMReady.

Although, in order for this to trigger you'd need a really large page considering it would have to be just pure dom rendering slowing the page down.

Is there any other possible way to inform user about slow loading of the page (particularly when some js or css file in the head is really big and takes some time to load)?

The above leads me to believe you'd be better off using jQuery(window).load rather than jQuery(document).ready. So you could replace the latter part of the above with:

/// on everything ready clear timeouts
jQuery(window).load(function(){
  clearInterval(tos.append);
  if ( tos.conceal && tos.reveal ) {
    clearTimeout(tos.reveal);
    clearTimeout(tos.conceal);
  }
});

This will only fire once everything has downloaded i.e. images, scripts, style and so on.

Without jQuery

This is also quite easy to implement in a crossbrowser way — more so than DOMReady — without the use of jQuery. We just need to make sure we don't wipe out any pre-existing onload listeners.

window.onload = (function(prev, ours){
  return function(e){
    ( ours && ours.call && ours.call( window, e ) );
    ( prev && prev.call && prev.call( window, e ) );
  };
})(window.onload, function(){
  clearInterval(tos.append);
  if ( tos.conceal && tos.reveal ) {
    clearTimeout(tos.reveal);
    clearTimeout(tos.conceal);
  }
});

If you want a more modern solution however, one that only worries about the top tier of browsers you could use:

window.addEventListener('load', function(e){
  clearInterval(tos.append);
  if ( tos.conceal && tos.reveal ) {
    clearTimeout(tos.reveal);
    clearTimeout(tos.conceal);
  }
});

... and with a little bit of crossbrowseriness added, perhaps something like:

var onload = function(){
  clearInterval(tos.append);
  if ( tos.conceal && tos.reveal ) {
    clearTimeout(tos.reveal);
    clearTimeout(tos.conceal);
  }
};

if ( window.attachEvent ) {
  window.attachEvent('onload', onload); // note the 'on' prefixed
}
else if ( window.addEventListener ) {
  window.addEventListener('load', onload);
}

Then you have a quick, library-free solution, which doesn't rely on alert dialogs.

like image 52
Pebbl Avatar answered Oct 07 '22 08:10

Pebbl