Как определить, загружены ли файлы JavaScript?
Есть ли событие, которое срабатывает при загрузке файлов JavaScript? Эта проблема возникла, потому что YSlow рекомендует перемещать JavaScript файлы в конец страницы. Это означает, что $(document).ready(function1)
срабатывает до загрузки js-файла, содержащего код для function1
.
Как избежать такой ситуации?
5 ответ(ов)
Я не имею под рукой ссылки на это, но теги <script>
обрабатываются по порядку. Если вы поместите ваш код $(document).ready(function1)
в тег <script>
после тех тегов, которые определяют function1
, то все должно сработать.
<script type='text/javascript' src='...'></script>
<script type='text/javascript' src='...'></script>
<script type='text/javascript'>
$(document).ready(function1);
</script>
Конечно, другой подход — это убедиться, что вы используете только один тег <script>
в целом, комбинируя файлы в процессе сборки. (Если только вы не загружаете другие скрипты с CDN.) Это также поможет улучшить воспринимаемую скорость загрузки вашей страницы.
UPDATE: Только что понял, что не ответил на ваш вопрос: не думаю, что существует кросс-браузерное событие, которое срабатывает Если постараться, такое событие есть, см. ниже. Вы можете проверить наличие символов и использовать setTimeout
для повторной проверки:
<script type='text/javascript'>
function fireWhenReady() {
if (typeof function1 !== 'undefined') {
function1();
} else {
setTimeout(fireWhenReady, 100);
}
}
$(document).ready(fireWhenReady);
</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
нужна, чтобы избежать дублирования уведомлений.
Когда говорят "внизу страницы", это не следует понимать дословно: речь идет о месте перед закрывающим тегом </body>
. Размещайте свои скрипты там, и они будут загружены до события DOMReady; если же вы поместите их после, DOM будет готов до того, как скрипты загрузятся (поскольку он завершен, когда парсится закрывающий тег </html>
), и, как вы уже заметили, это не будет работать.
Если вас интересует, откуда я это знаю: я работал в Yahoo!, и мы размещали наши скрипты прямо перед тегом </body>
😃
EDIT: также посмотрите ответ T.J. Crowder и убедитесь, что у вас все в правильном порядке.
Метод .load()
в jQuery используется для обработки события загрузки элементов, включая изображения и скрипты. В данном случае, вы привели код, который добавляет обработчик события загрузки для всех элементов <script>
на странице. Вот пояснение на русском языке, как это работает:
$('script').load(function () {
// Ваш код здесь будет выполняться после загрузки всех <script> элементов
});
Важно отметить, что метод .load()
применяется к элементам, которые уже загружены на момент вызова. Если вы хотите, чтобы ваш код выполнялся именно после завершения загрузки скриптов, вы должны убедиться, что этот код вызывается после того, как эти скрипты были добавлены в документ.
Также стоит упомянуть, что данный метод устарел в новых версиях jQuery (начиная с 3.0), и его рекомендуется заменять на обработку события $(window).on('load', function() { ... });
, если ваша цель — отследить загрузку всей страницы (включая все ресурсы).
Надеюсь, это поможет! Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать.
В дополнение к ответу @T.J. Crowder я добавил рекурсивный внешний цикл, который позволяет пройтись по всем скриптам в массиве и затем выполнить функцию, когда все скрипты загружены:
loadList([массив скриптов], 0, function() { // выполняйте ваши действия после загрузки скриптов });
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! Я с содроганием читал рекомендации о том, чтобы просто добавить пару секунд задержки перед выполнением колбэка, которые встречал в других темах.
Ваш подход к регистрации загрузки JavaScript файлов через вызов функции в конце каждого скрипта вполне допустим, и он должен работать во всех современных браузерах. Давайте рассмотрим реализацию немного подробнее.
В index.htm
вы можете определить свою функцию IAmReady
в заголовке:
<script>
let readyCalls = 0;
function IAmReady(id) {
readyCalls += 1;
// Логика для запуска кода после получения двух вызовов
if (readyCalls === 2) {
// Здесь ваш код
console.log('Оба скрипта загружены, выполняем код...');
}
}
</script>
Затем в конце Js1.js
и Js2.js
вы просто вызываете эту функцию с соответствующими параметрами:
// Js1.js
IAmReady(1);
// Js2.js
IAmReady(2);
Таким образом, когда оба скрипта будут загружены, функция IAmReady
будет вызвана дважды, и ваш код для инициализации выполнится только после того, как оба вызова произойдут.
Однако учтите, что если вы будете добавлять дополнительные JS файлы, вам нужно будет обновить логику внутри IAmReady
, чтобы следить за количеством этих вызовов. Этот метод прост, но может стать неуправляемым при большом количестве зависимостей. Возможно, стоит рассмотреть использование таких библиотек, как RequireJS или подобные средства для управления зависимостями и загрузкой модулей.
Как перенаправить на другую веб-страницу?
Прокрутка к элементу с использованием jQuery
Как определить нажатие клавиши Esc?
Как получить данные формы с помощью JavaScript/jQuery?
Как выполнить код после сброса HTML-формы с помощью jQuery?