11

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.

Community
  • 1
  • 1
Artyom Neustroev
  • 8,627
  • 5
  • 33
  • 57

5 Answers5

4

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.

Pebbl
  • 34,937
  • 6
  • 62
  • 64
1

A possible (but little messy solution):

Load your page in an iFrame and attach a ready event listener to the iFrame. Here's an example of how to do this

jQuery .ready in a dynamically inserted iframe

In this way you can control the outer page's DOM and at the same time monitoring the iFrame loading time.

Community
  • 1
  • 1
enriquecastl
  • 840
  • 5
  • 10
0

Document-Ready means the DOM has been read. You can execute code near before Document-Ready using this:

   ...
  </body>
  <script>window.clearInterval(GLOBAL_INTERVAL);</script>
</html>

This is more low-level, you should not use jQuery here.

Grim
  • 1,938
  • 10
  • 56
  • 123
0

how about checking the document.readyState

  setTimeout(function(){ 
    //after 3 seconds if the document is still not ready the alert will appear
    if(document.readyState=="loading")
     alert("The Internet connection is slow. Please continue waiting.");},3000);

  $(function () {
       alert("document ready");
  });

https://developer.mozilla.org/en-US/docs/Web/API/document.readyState?redirectlocale=en-US&redirectslug=DOM%2Fdocument.readyState

  • The thing is not detecting when the document is ready, I am familiar with that. I want to know, what is possible to do when it is not ready. – Artyom Neustroev Sep 06 '13 at 05:56
  • I' am sorry I don't get you, what you mean by it is not detecting when the document is ready? and isn't it showing `loading` before the document is ready!? It does for me –  Sep 06 '13 at 06:01
  • I mean, question is not about the states of the document. I know, when the document is ready. I want to do something like `alert` _BEFORE_ it is ready. – Artyom Neustroev Sep 06 '13 at 06:04
  • Yes, like that. But anything else except `alert()`. – Artyom Neustroev Sep 06 '13 at 07:20
  • window dialogs? modal dialogs? https://developer.mozilla.org/en-US/docs/Web/API/window.showModalDialog, http://msdn.microsoft.com/en-us/library/ms536759%28VS.85%29.aspx –  Sep 06 '13 at 09:02
0

Well, after several hours of hurting the brain, I've came to solution. This is more about better user experience, than technical innovation, but suits my needs.

The <script></script> is still at the top of <head></head>, every 30 seconds it asks user, if he wants to stay on the page and wait, until it loads. If user refuses, the window gets closed, otherwise loading continues. The script looks like the following:

(function () {
   var SLOW_CONNECTION = setInterval(function () {
      if (!confirm("The Internet connection speed is low. Do you want to continue waiting?")) {
         var win = window.open("", "_self");
         win.close();
      }
   }, 30000);
   window.addEventListener("load", function () {
      clearInterval(SLOW_CONNECTION);
   });
})();
Artyom Neustroev
  • 8,627
  • 5
  • 33
  • 57