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

этот вопрос уже есть ответ здесь:

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

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

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

window.onload="myFunction()";

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

<body onload="myFunction()">

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

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

Что такое кросс-браузер (Старый/Новый)-совместимый метод выдачи одной или нескольких функций таким образом, как jQuery $.ready()?

10 ответов


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

<html>
<head>
</head>
<body>
Your HTML here

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

})();
</script>
</body>
</html>

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

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

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

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

с запасным вариантом:

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

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

document.attachEvent("onreadystatechange", fn);

С a переход к:

window.attachEvent("onload", fn);

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


вот полная замена jQuery .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. создать жизнь (немедленно вызванное выражение функции) поэтому мы можем иметь непубличное состояние переменная.
  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 завершается, и он сохраняет порядок вызова.


Я хотел бы упомянуть некоторые из возможных путей здесь вместе с чистый 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 собственность. Если он содержит строку in (например,uninitialized и loading первые два состояние готовности DOM из 5) мы устанавливаем тайм-аут и проверяем снова. В противном случае, мы выполните переданную функцию.

и вот это jsFiddle для того,работает во всех браузерах.

спасибо Tutorialzine за включение этого в свою книгу.


если вы делаете ванилин простые JavaScript без jQuery, то вы должны использовать (Internet Explorer 9 или более поздней версии):

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

выше является эквивалентом jQuery .ready:

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

который также может быть написан стенографией, как это, который jQuery будет работать после готового даже происходит.

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

не путать С ниже (что не означает, что DOM готов):

не использовать жизнь как это самоисполняющееся:

 Example:

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

этот IIFE не будет ждать вашего DOM, чтобы загрузить. (Я даже говорю о последней версии браузера Chrome!)


протестировано в 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 или DOM ready без обратной совместимости. Вероятно, она нуждается в дальнейшей доработке. Тестирование в последних версиях 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
});

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

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


хорошие люди в HubSpot есть ресурс, где вы можете найти чистые методологии Javascript для достижения много jQuery добра-в том числе ready

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

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

<script>
   myFunction()
</script>
</body>
</html>

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


готов

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+


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

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

}

или:

window.onload = main;

function main(){
    // Code. . .

}

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

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 мс для запуска, однако, так что вот более сложный способ, который не должен:

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

см. также Как проверить, готов ли DOM без фреймворка?.


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

Кажется, что вы должны просто использовать jQuery min