Чистый JavaScript-эквивалент jQuery's $.ready() - как вызвать функцию, когда страница/DOM готова к этому

Ладно, возможно, это просто глупый вопрос, хотя я уверен, что множество других людей время от времени задают такой же вопрос. Я просто хочу быть уверенным на 100% в любом случае. С jQuery мы все знаем замечательную

$('document').ready(function(){});

Однако, допустим, я хочу запустить функцию, написанную на стандартном JavaScript без какой-либо библиотеки, и что я хочу запустить функцию, как только страница будет готова ее обработать. Как правильно к этому подойти?

Я знаю, что я могу сделать:

window.onload="myFunction()";

...или я могу использовать тег body:

<body onload="myFunction()">

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

<script type="text/javascript">
   myFunction();
</script>

Каков кроссбраузерный (старый/новый) совместимый метод выдачи одной или нескольких функций подобно jQuery's $.ready()?

Комментарии к вопросу (9)
Решение

Самое простое, что можно сделать в отсутствие фреймворка, который делает всю кроссбраузерную совместимость за вас, это просто поместить вызов вашего кода в конец тела. Это выполняется быстрее, чем обработчик onload, потому что он ждет только готовности DOM, а не загрузки всех изображений. И это работает в любом браузере.






Your HTML here

<script>
// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();
</script>


Для современных браузеров (начиная с IE9 и новее и любой версии Chrome, Firefox или Safari), если вы хотите иметь возможность реализовать метод jQuery типа $(document).ready(), который вы можете вызвать из любого места (не беспокоясь о том, где расположен вызывающий скрипт), вы можете просто использовать что-то вроде этого:

function docReady(fn) {
    // see if DOM is already available
    if (document.readyState === "complete" || document.readyState === "interactive") {
        // call on next available tick
        setTimeout(fn, 1);
    } else {
        document.addEventListener("DOMContentLoaded", fn);
    }
}    

Использование:

docReady(function() {
    // DOM is loaded and ready for manipulation here
});

Если вам нужна полная кросс-браузерная совместимость (включая старые версии IE) и вы не хотите ждать window.onload, то вам, вероятно, стоит посмотреть, как фреймворк вроде jQuery реализует свой метод $(document).ready(). Это довольно сложно, в зависимости от возможностей браузера.

Чтобы дать вам небольшое представление о том, что делает jQuery (это будет работать везде, где размещен тег script).

Если поддерживается, он пробует стандартный метод:

document.addEventListener('DOMContentLoaded', fn, false);

с отступлением на:

window.addEventListener('load', fn, false )

или для старых версий IE используется:

document.attachEvent("onreadystatechange", fn);

с возможностью возврата к:

window.attachEvent("onload", fn);

И, есть некоторые обходные пути в коде IE, которые я не совсем понимаю, но похоже, что это как-то связано с фреймами.


Вот полная замена jQuery's .ready(), написанная на обычном javascript:

(function(funcName, baseObj) {
    // The public function name defaults to window.docReady
    // but you can pass in your own object and own function name and those will be used
    // if you want to put them in a different namespace
    funcName = funcName || "docReady";
    baseObj = baseObj || window;
    var readyList = [];
    var readyFired = false;
    var readyEventHandlersInstalled = false;

    // call this when the document is ready
    // this function protects itself against being called more than once
    function ready() {
        if (!readyFired) {
            // this must be set to true before we start calling callbacks
            readyFired = true;
            for (var i = 0; i < readyList.length; i++) {
                // if a callback here happens to add new ready handlers,
                // the docReady() function will see that it already fired
                // and will schedule the callback to run right after
                // this event loop finishes so all handlers will still execute
                // in order and no new ones will be added to the readyList
                // while we are processing the list
                readyList[i].fn.call(window, readyList[i].ctx);
            }
            // allow any closures held by these functions to free
            readyList = [];
        }
    }

    function readyStateChange() {
        if ( document.readyState === "complete" ) {
            ready();
        }
    }

    // This is the one public interface
    // docReady(fn, context);
    // the context argument is optional - if present, it will be passed
    // as an argument to the callback
    baseObj[funcName] = function(callback, context) {
        if (typeof callback !== "function") {
            throw new TypeError("callback for docReady(fn) must be a function");
        }
        // if ready has already fired, then just schedule the callback
        // to fire asynchronously, but right away
        if (readyFired) {
            setTimeout(function() {callback(context);}, 1);
            return;
        } else {
            // add the function and context to the list
            readyList.push({fn: callback, ctx: context});
        }
        // if document already ready to go, schedule the ready function to run
        if (document.readyState === "complete") {
            setTimeout(ready, 1);
        } else if (!readyEventHandlersInstalled) {
            // otherwise if we don't have event handlers installed, install them
            if (document.addEventListener) {
                // first choice is DOMContentLoaded event
                document.addEventListener("DOMContentLoaded", ready, false);
                // backup is window load event
                window.addEventListener("load", ready, false);
            } else {
                // must be IE
                document.attachEvent("onreadystatechange", readyStateChange);
                window.attachEvent("onload", ready);
            }
            readyEventHandlersInstalled = true;
        }
    }
})("docReady", window);

Последняя версия кода находится в открытом доступе на GitHub по адресу https://github.com/jfriend00/docReady.

Использование:

// pass a function reference
docReady(fn);

// use an anonymous function
docReady(function() {
    // code here
});

// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);

// use an anonymous function with a context
docReady(function(context) {
    // code here that can use the context argument that was passed to docReady
}, ctx);

Это было протестировано в:

IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices

Рабочая реализация и тестовый стенд: http://jsfiddle.net/jfriend00/YfD3C/


Вот краткое описание того, как это работает:

  1. Создаем IIFE (немедленно вызываемое функциональное выражение), чтобы иметь непубличные переменные состояния.
  2. Объявляем публичную функцию docReady(fn, context).
  3. Когда вызывается docReady(fn, context), проверяем, сработал ли уже обработчик готовности. Если да, просто запланируйте новый добавленный обратный вызов сразу после завершения этого потока JS с помощью setTimeout(fn, 1).
  4. Если обработчик готовности еще не сработал, то добавьте этот новый обратный вызов в список обратных вызовов, которые будут вызваны позже.
  5. Проверьте, готов ли уже документ. Если да, то выполните все обработчики готовности.
  6. Если мы еще не установили слушателей событий, чтобы знать, когда документ будет готов, то установите их сейчас.
  7. Если document.addEventListener существует, то установите обработчики событий с помощью .addEventListener() для событий "DOMContentLoaded" и "load". Событие "load" является резервным событием для безопасности и не должно быть необходимым.
  8. Если document.addEventListener не существует, то установите обработчики событий с помощью .attachEvent() для событий "onreadystatechange" и "onload".
  9. В событии onreadystatechange проверьте, является ли document.readyState === "complete" и если да, вызовите функцию для запуска всех обработчиков готовности.
  10. Во всех остальных обработчиках событий вызовите функцию для запуска всех обработчиков готовности.
  11. В функции, вызывающей все обработчики готовности, проверьте переменную состояния, чтобы узнать, сработали ли мы уже. Если да, то ничего не делайте. Если мы еще не были вызваны, пройдитесь по массиву функций готовности и вызовите каждую из них в том порядке, в котором они были добавлены. Установите флаг, указывающий на то, что все они были вызваны, чтобы они никогда не выполнялись более одного раза.
  12. Очистите массив функций, чтобы освободить все закрытия, которые они могли использовать.

Обработчики, зарегистрированные с помощью docReady(), гарантированно будут запущены в том порядке, в котором они были зарегистрированы.

Если вы вызываете docReady(fn) после того, как документ уже готов, обратный вызов будет запланирован на выполнение, как только текущий поток выполнения завершится с помощью setTimeout(fn, 1). Это позволяет вызывающему коду всегда считать, что это асинхронные обратные вызовы, которые будут вызваны позже, даже если позже - это как только завершится текущий поток JS, и сохраняет порядок вызовов.

Комментарии (16)

Я хотел бы упомянуть некоторые из возможных путей здесь вместе с чистого JavaScript трюк, который работает во всех браузерах:

// with jQuery 
$(document).ready(function(){ /* ... */ });

// shorter jQuery version 
$(function(){ /* ... */ });

// without jQuery (doesn't work in older IEs)
document.addEventListener('DOMContentLoaded', function(){ 
    // your code goes here
}, false);

// and here's the trick (works everywhere)
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
// use like
r(function(){
    alert('DOM Ready!');
});

Хитрость здесь, как пояснил автор, заключается в том, что мы проверяем, документ.в свойстве readyState собственность. Если он содержит строку в (как в не инициализирована и загрузки, первые два дом готов Штатов из 5) мы устанавливаем таймаут и снова проверить. В противном случае, мы выполняем переданную функцию.

И здесь'ы [jsFiddle][3] для трюк, который работает во всех браузерах.

Спасибо Tutorialzine для включения в свою книгу.

Комментарии (11)

Если вы делаете ваниль обычная язык JavaScript без jQuery, то вы должны использовать (интернет&ампер;усилитель; nbsp;Обозреватель&ампер;усилитель; nbsp;9 или более поздней версии):

document.addEventListener("DOMContentLoaded", function(event) {
    // Your code to run since DOM is loaded and ready
});

Выше эквивалент в jQuery .готов:

$(document).ready(function() {
    console.log("Ready!");
});

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

$(function() {
    console.log("ready!");
});

Не путать с ниже (которая не претендует на дом готовы):

Не используйте жизнь такой, что имеет самостоятельного выполнения:

 Example:

(function() {
   // Your page initialization code here  - WRONG
   // The DOM will be available here   - WRONG
})();

Эта жизнь не будет ждать для Ваш дом, чтобы загрузить. (Я'м даже не говорю о последней версии браузера Хром!)

Комментарии (3)

Испытания в IE9, и последний Firefox и Chrome, а также поддерживается в IE8.

document.onreadystatechange = function () {
  var state = document.readyState;
  if (state == 'interactive') {
      init();
  } else if (state == 'complete') {
      initOnCompleteLoad();
  }
}​;

Пример: http://jsfiddle.net/electricvisions/Jacck/

Обновление - многоразовые версия

Я просто развил следующее. Это'ы довольно упрощенный эквивалент в jQuery или дом готов без обратной совместимости. Он, вероятно, нуждается в дальнейшей доработке. Тестирование в последних версиях Chrome, Firefox и IE (10/11) и должны работать в старых браузерах, как прокомментировал. Я'будете обновлять, если я найду какие-либо вопросы.

window.readyHandlers = [];
window.ready = function ready(handler) {
  window.readyHandlers.push(handler);
  handleState();
};

window.handleState = function handleState () {
  if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
    while(window.readyHandlers.length > 0) {
      (window.readyHandlers.shift())();
    }
  }
};

document.onreadystatechange = window.handleState;

Использование:

ready(function () {
  // your code here
});

Это's написано для обработки асинхронной загрузки JS, но вы, возможно, захотите синхронизация загрузите этот скрипт, если вы не'вновь сокращение. Я'вэ нашел его полезным в развитии.

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

Комментарии (2)

Хорошие люди в HubSpot есть ресурс, где можно найти чисто методологии JavaScript для достижения много jQuery и добра - в том числе и "готово"

http://youmightnotneedjquery.com/#ready

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fn);
  } else {
    document.attachEvent('onreadystatechange', function() {
      if (document.readyState != 'loading')
        fn();
    });
  }
}

пример рядный использование:

ready(function() { alert('hello'); });
Комментарии (3)

Я'м не совсем уверен, что вы'повторно просить, но, может быть, это может помочь:

window.onload = function(){
    // Code. . .

}

Или:

window.onload = main;

function main(){
    // Code. . .

}
Комментарии (3)

Ваш метод (размещение скрипта перед закрывающим тегом body)

<script>
   myFunction()
</script>

это надежный способ поддержки старых и новых браузеров.

Комментарии (2)

Готов

function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}

Использовать как

ready(function(){
    //some code
});

Для самостоятельного вызова код

(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){

    //Some Code here
    //DOM is avaliable
    //var h1s = document.querySelector("h1");

});

Поддержка: в IE9+

Комментарии (1)

Здесь'ы очищенную, номера-ивал-через версия ОЗУ-Сваруп'С, что "работает во всех браузерах, что" Выбор-работает во всех браузерах!

function onReady(yourMethod) {
  var readyStateCheckInterval = setInterval(function() {
    if (document && document.readyState === 'complete') { // Or 'interactive'
      clearInterval(readyStateCheckInterval);
      yourMethod();
    }
  }, 10);
}
// use like
onReady(function() { alert('hello'); } );

Это, однако, подождать лишние 10 мс для запуска, так вот's более сложный путь, который должен'т:

function onReady(yourMethod) {
  if (document.readyState === 'complete') { // Or also compare to 'interactive'
    setTimeout(yourMethod, 1); // Schedule to run immediately
  }
  else {
    readyStateCheckInterval = setInterval(function() {
      if (document.readyState === 'complete') { // Or also compare to 'interactive'
        clearInterval(readyStateCheckInterval);
        yourMethod();
      }
    }, 10);
  }
}

// Use like
onReady(function() { alert('hello'); } );

// Or
onReady(functionName);

Смотрите также https://stackoverflow.com/questions/8100576/how-to-check-if-dom-is-ready-without-a-framework.

Комментарии (0)

document.ondomcontentready=function(){} должен сделать трюк, но он не имеет полной совместимости с браузерами.

Похоже, что вам следует просто использовать jQuery min

Комментарии (5)