Как проверить, готова ли DOM без рамки?

Вопрос так похож на миллион других здесь и в Интернете. Как проверить, загружен ли DOM в Javascript? Но вот улов:

  • Без использования фреймворка, такого как jQuery и т.д.
  • Не зная, загружен ли ваш script через статически размещенный тег <script> или через какой-либо другой Javascript гораздо позже после того, как DOM уже загружен.

Можно ли это сделать более или менее надежно и с кросс-браузерной совместимостью?

Добавлено: Позвольте мне пояснить: я пишу автономный файл .JS, который может быть включен в произвольные веб-страницы. Я хочу выполнить код ПОСЛЕ, DOM был загружен. Но я не знаю КАК мой script будет включен. Это может быть путем размещения тега <script> (в этом случае будут использоваться традиционные решения onload или DOM-готовность); или он может быть загружен через AJAX или некоторые другие средства, намного позже после того, как DOM уже загружен (так что ранее упомянутые решения никогда не будут срабатывать).

Ответ 1

Свойство document.readyState можно использовать для проверки готовности документа. Из MDN:

Значения

ReadyState документа может быть одним из следующих:

  • загрузка - документ все еще загружается.
  • интерактивный - документ завершил загрузку, и документ был проанализирован, но все еще загружаются подресурсы, такие как изображения, таблицы стилей и рамки.
  • завершено - документ и все подресурсы завершили загрузку. Состояние указывает, что событие load вот-вот сработает.

Пример кода:

if(document.readyState === "complete") {
    // Fully loaded!
}
else if(document.readyState === "interactive") {
    // DOM ready! Images, frames, and other subresources are still downloading.
}
else {
    // Loading still in progress.
    // To wait for it to complete, add "DOMContentLoaded" or "load" listeners.

    window.addEventListener("DOMContentLoaded", () => {
        // DOM ready! Images, frames, and other subresources are still downloading.
    });

    window.addEventListener("load", () => {
        // Fully loaded!
    });
}

Ответ 2

В браузерах Firefox, Opera и Webkit есть событие уровня документа DOMContentLoaded, которое вы можете прослушать с помощью document.addEventListener("DOMContentLoaded", fn, false).

Это сложнее в IE. Что делает jQuery в IE, это смотреть onreadystatechange на объект документа для определенного readystate с резервной копией события document.onload. document.onload срабатывает позже, чем DOM готов (только когда все изображения закончили загрузку), поэтому он используется только в качестве блокиратора обратного хода, если предыдущие события не работают по какой-либо причине.

Если вы потратите некоторое время на Google, вы найдете код для этого. Я считаю, что наиболее проверенный код для этого - в больших рамках, таких как jQuery и YUI, поэтому, даже если я не использую эту структуру, я смотрю их исходный код для техник.

Здесь основная часть источника jQuery 1.6.2 для document.ready():

bindReady: function() {
    if ( readyList ) {
        return;
    }

    readyList = jQuery._Deferred();

    // Catch cases where $(document).ready() is called after the
    // browser event has already occurred.
    if ( document.readyState === "complete" ) {
        // Handle it asynchronously to allow scripts the opportunity to delay ready
        return setTimeout( jQuery.ready, 1 );
    }

    // Mozilla, Opera and webkit nightlies currently support this event
    if ( document.addEventListener ) {
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

        // A fallback to window.onload, that will always work
        window.addEventListener( "load", jQuery.ready, false );

    // If IE event model is used
    } else if ( document.attachEvent ) {
        // ensure firing before onload,
        // maybe late but safe also for iframes
        document.attachEvent( "onreadystatechange", DOMContentLoaded );

        // A fallback to window.onload, that will always work
        window.attachEvent( "onload", jQuery.ready );

        // If IE and not a frame
        // continually check to see if the document is ready
        var toplevel = false;

        try {
            toplevel = window.frameElement == null;
        } catch(e) {}

        if ( document.documentElement.doScroll && toplevel ) {
            doScrollCheck();
        }
    }
},

Ответ 3

Если полагаться на document.readyState в порядке, быстрое и грязное решение с опросом:

(function() {
    var state = document.readyState;
    if(state === 'interactive' || state === 'complete') {
        // do stuff
    }
    else setTimeout(arguments.callee, 100);
})();

Ответ 4

Это работает для всех браузеров и является коротким и кратким:

var execute = function () {
  alert("executing code");  
};

if ( !!(window.addEventListener) )
  window.addEventListener("DOMContentLoaded", execute)
else // MSIE
  window.attachEvent("onload", execute)

Ответ 5

Событие DOMContentLoaded запускается, когда исходный HTML-документ полностью загружен и проанализирован, не дожидаясь завершения стилей, изображений и подкадров, чтобы завершить загрузку. Хорошая вещь: хром, firefox, IE9, опера и сафари поддерживают его в равной степени

document.addEventListener("DOMContentLoaded", function(event) 
{
    console.log("DOM fully loaded and parsed");
}

ПРИМЕЧАНИЕ. Internet Explorer 8 поддерживает событие readystatechange, которое может использоваться для обнаружения, когда DOM готов.

Ответ 6

Вот один из способов, запустив script в нижней части страницы. Кроме того, используя window.onload, вы можете дождаться загрузки всех изображений/скриптов. Или вы можете просто поместить код внизу, не дожидаясь загрузки изображений.

<html>
<head>
</head>
<body>
</body>
<script language="text/javascript">
  window.onload = (function (oldOnLoad) {
    return function () {
      if (oldOnLoad) { 
        olOnLoad();  //fire old Onload event that was attached if any.
      }
      // your code to run after images/scripts are loaded
    }
  })(window.onload);

  // your code to run after DOM is loaded
</script>
</html>

Отредактировано: для комментария Vilx

Многие привязки onload - это пример http://jsfiddle.net/uTF2N/3/