Возможные действия до того, как документ будет готов

Проблема

Я написал script для информирования пользователя о том, что страница медленно загружается (скажем, из-за медленного подключения к Интернету). script помещается сначала в <head></head> и достаточно прост:

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);
});

Вопрос

В текущем примере информация просто предупреждается. Есть ли другой способ информировать пользователя о медленной загрузке страницы (особенно когда какой-то файл js или css в голове действительно большой и требуется некоторое время для загрузки)? Я пробовал манипулировать DOM (что, на мой взгляд, неправильно делать, пока документ не готов), а document.body привел к null.

Дополнительные

Решение с настройкой интервала от здесь. Любые другие идеи о том, как это сделать, очень ценятся.

Ответ 1

Хорошо, после нескольких часов вреда мозгу я пришел к решению. Это больше касается лучшего пользовательского опыта, чем технических новшеств, но подходит для моих потребностей.

<script></script> по-прежнему находится на вершине <head></head>, каждые 30 секунд он запрашивает пользователя, если он хочет оставаться на странице и ждать, пока он не загрузится. Если пользователь отказывается, окно закрывается, в противном случае загрузка продолжается. script выглядит следующим образом:

(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);
   });
})();

Ответ 2

Если бы это был я, я бы, наверное, попробовал что-то вроде этого:

<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>

Со следующей разметкой сразу после <body>

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

И следующая разметка перед </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>

Поместив этот script непосредственно перед тегом body body, вы можете получить доступ ко всем ранее проанализированным элементам DOM, вам не нужно ждать DOMReady.

Хотя для того, чтобы это было вызвано, вам понадобится действительно большая страница, учитывая, что это будет просто чистый рендеринг дома, замедляющий страницу вниз.

Есть ли другой способ сообщить пользователю о медленной загрузке страницы (, особенно когда некоторые js или css файлы в голове действительно большие и требуется некоторое время для загрузки)?

Приведенное выше приводит меня к мысли, что вам лучше использовать jQuery(window).load, а не jQuery(document).ready. Таким образом, вы можете заменить последнюю часть выше:

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

Это будет срабатывать только после того, как все скачано, например, изображения, сценарии, стиль и т.д.

Без jQuery

Это также довольно легко реализовать в режиме crossbrowser — больше, чем DOMReady — без использования jQuery. Нам просто нужно убедиться, что мы не уничтожаем ранее существовавших слушателей onload.

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);
  }
});

Если вам требуется более современное решение, которое беспокоит только верхний уровень браузеров, который вы можете использовать:

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

... и с добавлением немного кроссбраузерности, возможно, что-то вроде:

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);
}

Затем у вас есть быстрое, без библиотечного решения, которое не полагается на диалоговые окна предупреждений.

Ответ 3

Возможное (но немного грязное решение):

Загрузите свою страницу в iFrame и присоедините готовый прослушиватель событий к iFrame. Вот пример того, как это сделать

jQuery.ready в динамически вставленном iframe

Таким образом вы можете контролировать внешний DOM внешней страницы и одновременно контролировать время загрузки iFrame.

Ответ 4

Document-Ready означает, что DOM был прочитан. Вы можете выполнить код рядом с Document-Ready, используя это:

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

Это более низкий уровень, вы не должны использовать jQuery здесь.