Является ли обратный вызов jQuery getScript() ненадежным или я делаю что-то неправильно?
Я использую следующий бит script для загрузки другого:
$.getScript("CAGScript.js", function () {
try {
CAGinit();
} catch(err) {
console.log(err);
}
});
Идея состоит в том, что $.getScript загружает script, а затем выполняет обратный вызов, когда это делается. CAGInit()
- это функция, которая находится в CAGScript.js
.
Проблема в том, что примерно половина времени CAGInit()
не срабатывает (в любом браузере). Вход в консоль Firebug сообщает, что он не определен. В остальное время он отлично работает.
Есть ли у кого-нибудь идеи, что я делаю неправильно?
Спасибо.
Ответы
Ответ 1
Если файл хранится в том же домене, тогда jQuery будет использовать XHR для извлечения его содержимого, а затем глобально "eval". Это должно работать нормально, но если у вас возникли проблемы, я бы предложил использовать альтернативный метод вставки тега script. К сожалению, jQuery не раскрывает эту функциональность, поэтому вам придется сделать это самостоятельно:
var script = jQuery('<script/>').attr('src', 'CAGSCript.js').appendTo('head');
var timer = setInterval( function(){
if (window.CAGInit !== undefined) {
clearInterval(timer);
script.remove();
// Do your stuff:
CAGInit();
}
}, 200);
Лучше всего отнести это к функции; выше всего лишь пример...
Ответ 2
Я заметил ту же проблему с FF 3.6.
Решением является загрузка script синхронно.
Как упоминалось в документации jQuery, getScript сокращен для:
$.ajax({
url: url,
dataType: 'script',
success: success
});
Все работает отлично, если вместо getScript использовать следующее:
$.ajax({
url: url,
dataType: 'script',
success: success,
async: false
});
Ответ 3
Просто хотел предложить некоторое понимание, которое я имею по этой проблеме. Обратный вызов не будет срабатывать, если в коде, который вы загружаете, есть ошибка, и (по крайней мере, в Chrome с jQuery 1.7.1) ошибка будет проглатываться. Я обнаружил, что у меня была отвратительная фигурная скобка из автозаполнения в коде, который я загружал, и функция обратного вызова не срабатывала. Прерывистое поведение здесь может быть вызвано изменением загруженного кода между тестами.
Ответ 4
У той же проблемы была проблема с firefox, и она немного переделала.
Применяя его к вашему примеру:
$.getScript("CAGScript.js", function (xhr) {
try {
CAGinit();
} catch(err) {
eval(xhr);
CAGinit();
}
});
В основном заставляет оценивать XHR-ответ, если он сам по себе не выполняет.
Ответ 5
Я тоже немного разбираюсь в Chrome. jQuery иногда вызывает обратный вызов успеха, как будто все хорошо, но script на самом деле не загружен должным образом. В нашем случае решение состояло в том, чтобы просто перейти от надежного jQuery:
<script>
$.getScript("helpers.js", function () {
// use helpers....or: EXPLODE (wheeeee!)
helpers.doSomething();
});
</script>
Чтобы доверять браузеру:
<script src="helpers.js"></script>
<script>
helpers.doSomething();
</script>
Я снова и снова обнаруживаю, что "меньше jQuery == меньше случаев края == меньше ошибок". И обычно более читаемый код тоже!
Ответ 6
Чтобы убедиться, что CAGScript.js ЗАГРУЖЕН и ВЫПОЛНИЛСЯ до вызова функции CAGinit, самым верным способом является вызов функции внутри CAGScript.js.
CAGScript.js:
...
/*
your code
*/
function CAGinit(){
...
}
...
/* last line */
CAGinit();
а затем в вашем основном файле просто вызовите getScript():
$.getScript("CAGScript.js");
Ответ 7
Да, я также обнаружил, что getScript ненадежен в FireFox, уворачивая обратный вызов до того, как script был загружен и/или выполнен. (Использование JQuery 1.41 и FireFox 3.6. Проблема, похоже, не затрагивает IE, Chrome или Opera.)
Я не проводил обширное тестирование, но, похоже, это происходит только с некоторыми конкретными сценариями... не знаю, почему.
Предложение RaYell не работает, поскольку getScript сообщает об успехе, хотя script еще не был оценен. В большинстве случаев предложение Pieter заставляет код анализировать дважды, что является неэффективным и может вызвать ошибки.
Эта альтернатива, похоже, работает там, где getScript не работает. Обратите внимание, что это похоже на добавление элемента script DOM, тогда как getScript делает XHR.
http://www.diveintojavascript.com/projects/sidjs-load-javascript-and-stylesheets-on-demand
Ответ 8
Я думаю, вы можете начать с проверки функции testStatus функции обратного вызова, чтобы убедиться, что script действительно загружен. Функция обратного вызова имеет два параметра, более эффективные для тех, которые вы можете найти на jQuery Docs
$.getScript("CAGScript.js", function (data, textStatus) {
if (textStatus === "success") {
try {
CAGinit();
} catch(err) {
console.log(err);
}
} else {
console.log("script not loaded");
}
});
Ответ 9
Я хотел иметь что-то похожее на auto_load в PHP, реализованном в JS, типичное решение использует try-catch для всех функций. Когда функция отсутствует, мы переходим к загрузке ее библиотеки.
Мое решение взято из решения Pieter следующим образом:
function CheckUserPW(username,password){
try{
loginCheckUserPW(username,password);
} catch(err) {
$.getScript('login.js', function(xhr){
eval(xhr);
loginCheckUserPW(username,password);
});
}
}
Ответ 10
Кажется, что jQuery обрабатывает кросс-доменные и одни и те же запросы домена только сейчас. Для междоменных запросов он добавит тэг script и подпишится на ошибки и события загрузки и соответствующим образом вызовет ваши обратные вызовы и ошибки, это ошибка только в случае сбоя запроса, ошибки, оценивающие script, будут по-прежнему считаться успешными что касается запроса. Для одного и того же происхождения он выполнит запрос XHR, а затем выполнит команду globalEval и после этого вызовет ваш обратный вызов, если что-то не удастся в процессе, оно вызовет обратный вызов ошибки.
Использование XHR имеет несколько проблем, оно разбивает отладчик, sourcemaps и полагается на globalEval, у которого есть проблемы с ContentSecurityPolicy. Для этого мы просто добавляем тег script при загрузке скриптов.
var scriptElement = $("<script>").prop({src: url, async: true});
scriptElement.one('load', ()=> ...);
scriptElement.one('error', (evt)=> ...);
document.head.appendChild(scriptElement[0]);
Если вы хотите сделать это без поиска jQuery для динамического импорта скриптов в в этой статье
Надеюсь, это поможет.
Ответ 11
Мой способ
setTimeout(function(){
$.getScript( "CAGScript.js");
},
2000);
та же проблема, с которой мы сталкиваемся в angular, также когда мы хотим обновлять данные в $scope и решается с помощью $timeout таким же образом в angular...