Как определить, загружены ли файлы javascript?

Есть ли событие, которое запускается при загрузке файлов JavaScript? Проблема возникла из-за того, что YSlow рекомендует переместить файлы JavaScript в нижней части страницы. Это значит, что $(document).ready(function1) запускается перед загрузкой js файла, содержащего код для function1.

Как избежать такой ситуации?

Ответ 1

У меня нет ссылки на нее удобно, но теги script обрабатываются по порядку, и поэтому, если вы поместите свой $(document).ready(function1) в тег script после тегов script, которые определяют функцию1, и т.д.., вам должно быть хорошо идти.

<script type='text/javascript' src='...'></script>
<script type='text/javascript' src='...'></script>
<script type='text/javascript'>
$(document).ready(function1);
</script>

Конечно, другой подход состоял бы в том, чтобы вы использовали только один тег script, в общем, путем объединения файлов как части процесса сборки. (Если вы не загружаете другие из CDN где-нибудь). Это также поможет улучшить воспринимаемую скорость вашей страницы.

EDIT: Только что понял, что я на самом деле не ответил на ваш вопрос: Я не думаю, что там было запущено кросс-браузерное событие, нет. Есть, если вы достаточно усердно работаете, см. ниже, Вы можете проверить символы и использовать setTimeout для перепланирования:

<script type='text/javascript'>
function fireWhenReady() {
    if (typeof function1 != 'undefined') {
        function1();
    }
    else {
        setTimeout(fireWhenReady, 100);
    }
}
$(document).ready(fireWhenReady);
</script>

... но вам не придется этого делать, если вы правильно настроили тэг script.


Обновление. Вы можете получать уведомления о загрузке для script элементов, которые вы добавляете на страницу динамически, если хотите. Чтобы получить широкую поддержку браузера, вам нужно сделать две разные вещи, но в качестве комбинированного метода это работает:

function loadScript(path, callback) {

    var done = false;
    var scr = document.createElement('script');

    scr.onload = handleLoad;
    scr.onreadystatechange = handleReadyStateChange;
    scr.onerror = handleError;
    scr.src = path;
    document.body.appendChild(scr);

    function handleLoad() {
        if (!done) {
            done = true;
            callback(path, "ok");
        }
    }

    function handleReadyStateChange() {
        var state;

        if (!done) {
            state = scr.readyState;
            if (state === "complete") {
                handleLoad();
            }
        }
    }
    function handleError() {
        if (!done) {
            done = true;
            callback(path, "error");
        }
    }
}

По моему опыту, уведомление об ошибке (onerror) не является 100% -ным кросс-браузером. Также обратите внимание, что некоторые браузеры будут выполнять оба механизма, следовательно, переменную done, чтобы избежать дублирования уведомлений.

Ответ 2

Когда они говорят "внизу страницы", они буквально не означают нижнее: они означают перед закрывающим тегом </body>. Поместите там свои скрипты, и они будут загружены перед событием DOMReady; поместите их позже, и DOM будет готов до их загрузки (потому что он завершается при анализе закрывающего тега </html>), который, как вы нашли, не будет работать.

Если вам интересно, как я знаю, что это то, что они означают: я работал в Yahoo! и мы помещаем наши скрипты непосредственно перед тегом </body>: -)

EDIT: также см. T.J. Crowder ответьте и убедитесь, что у вас есть вещи в правильном порядке.

Ответ 4

Я всегда звоню с конца файлов JavaScript для регистрации его загрузки, и он работал идеально для меня для всех браузеров.

Ex: У меня есть index.htm, Js1.js и Js2.js. Я добавляю функцию IAmReady (Id) в заголовок index.htm и вызываю ее с параметрами 1 и 2 с конца файлов, Js1 и Js2 соответственно. Функция IAmReady будет иметь логику для запуска загрузочного кода, когда он получит два вызова (сохраняя количество вызовов в статической/глобальной переменной) из двух js файлов.

Ответ 5

Далее к @T.J. Crowder answer, я добавил рекурсивный внешний цикл, который позволяет выполнять итерацию всех скриптов в массиве, а затем выполнять функцию после загрузки всех скриптов:

loadList([array of scripts], 0, function(){// do your post-scriptload stuff})

function loadList(list, i, callback)
{
    {
        loadScript(list[i], function()
        {
            if(i < list.length-1)
            {
                loadList(list, i+1, callback);  
            }
            else
            {
                callback();
            }
        })
    }
}

Конечно, вы можете сделать оболочку, чтобы избавиться от "0", если хотите:

function prettyLoadList(list, callback)
{
    loadList(list, 0, callback);
}

Хорошая работа @T.J. Crowder - я прижимался к "просто добавлю задержку в пару секунд до запуска обратного вызова", который я видел в других потоках.

Ответ 6

Измените порядок загрузки ваших сценариев, чтобы function1 был определен перед использованием его в обратном вызове ready.

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

Ответ 7

Подобно T.J. написал: порядок определен (по крайней мере, он последователен, когда ваш браузер собирается выполнить какой-либо JavaScript, даже если он может каким-то образом загрузить скрипты). Однако, поскольку, по-видимому, у вас проблемы, возможно, вы используете сторонние библиотеки JavaScript, которые дают 404 Not Found или тайм-аут? Если это так, прочитайте Лучший способ использования jQuery в Google Googles, но вернитесь к моей размещенной библиотеке в Google.