Есть много потенциальных ответов на этот вопрос. Мой ответ, очевидно, основан на ряде из них. Это то, чем я закончил, прочитав все ответы.
Проблема с $.getScript
и действительно любым другим решением, которое требует обратного вызова при завершении загрузки, заключается в том, что если у вас есть несколько файлов, которые используют его и зависят друг от друга, у вас больше нет способа узнать, когда все сценарии были загружен (если они вложены в несколько файлов).
Пример:
file3.js
var f3obj = "file3";
// Define other stuff
file2.js:
var f2obj = "file2";
$.getScript("file3.js", function(){
alert(f3obj);
// Use anything defined in file3.
});
file1.js:
$.getScript("file2.js", function(){
alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
alert(f2obj);
// Use anything defined in the loaded script...
});
Вы правы, когда говорите, что можете указать, что Ajax должен запускаться синхронно, или использовать XMLHttpRequest , но в настоящее время наблюдается тенденция отклонять синхронные запросы, поэтому вы можете не получить полную поддержку браузера сейчас или в будущее.
Вы можете попытаться использовать $.when
для проверки массива отложенных объектов, но теперь вы делаете это в каждом файле, и файл2 будет считаться загруженным, как только $.when
будет выполнено, а не при выполнении обратного вызова, поэтому file1 все еще продолжает выполнение до загрузки file3. Это действительно до сих пор та же проблема.
Я решил идти назад, а не вперед. Спасибо document.writeln
. Я знаю, что это табу, но при правильном использовании это работает хорошо. В итоге получается код, который можно легко отладить, правильно отображать в DOM и обеспечивать порядок загрузки зависимостей.
Конечно, вы можете использовать $ ("body"). Append (), но тогда вы больше не сможете корректно отлаживать.
ПРИМЕЧАНИЕ: Вы должны использовать это только во время загрузки страницы, в противном случае вы получите пустой экран. Другими словами, всегда помещайте это перед / вне документа .ready . Я не проверял использование этого после загрузки страницы в событии щелчка или чем-то подобном, но я почти уверен, что это не удастся.
Мне понравилась идея расширения jQuery, но, очевидно, вам не нужно.
Перед вызовом document.writeln
он проверяет, что скрипт еще не загружался, оценивая все элементы скрипта.
Я предполагаю, что скрипт не выполняется полностью, пока не будет выполнено его событие document.ready
. (Я знаю, что использование document.ready
не требуется, но многие люди используют его, и обращение с ним является гарантией.)
Когда дополнительные файлы загружены, обратные вызовы document.ready
будут выполняться в неправильном порядке. Чтобы решить эту проблему, когда скрипт действительно загружен, импортированный скрипт снова импортируется, и выполнение останавливается. Это приводит к тому, что для исходного файла теперь выполняется обратный вызов document.ready
после любого из любых импортируемых им сценариев.
Вместо этого вы можете попытаться изменить jQuery readyList
, но это выглядело как худшее решение.
Решение:
$.extend(true,
{
import_js : function(scriptpath, reAddLast)
{
if (typeof reAddLast === "undefined" || reAddLast === null)
{
reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
}
var found = false;
if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
{
found = $('script').filter(function () {
return ($(this).attr('src') == scriptpath);
}).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
}
if (found == false) {
var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.
document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln
if (reAddLast)
{
$.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
}
return true;
}
return false;
}
});
Использование:
file3:
var f3obj = "file3";
// Define other stuff
$(function(){
f3obj = "file3docready";
});
File2:
$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
f2obj = "file2docready";
});
File1:
$.import_js('js/file2.js');
// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"
$(function(){
// Use objects from file2 or file3 some more.
alert(f3obj); //"file3docready"
alert(f2obj); //"file2docready"
});