Обработка кода, который опирается на jQuery перед загрузкой jQuery
Я хотел бы следовать общему руководству по размещению всего JavaScript в самой нижней части страницы, чтобы ускорить время загрузки, а также позаботиться о некоторых неприятных проблемах с конфликтующими версиями jQuery в веб-приложении (Django).
Однако, каждый так часто у меня есть код, который зависит от jQuery, но который должен быть далее на странице (в основном код не может быть перенесен в нижнюю часть).
Мне интересно, есть ли простой способ закодировать это, так что, хотя jQuery еще не определен, код работает, когда jQuery определен.
Следующее, кажется, я должен сказать, как overkill, но я не знаю другого способа сделать это:
function run_my_code($) {
// jquery-dependent code here
$("#foo").data('bar', true);
}
var t = null;
function jquery_ready() {
if (window.jQuery && window.jQuery.ui) {
run_my_code(window.jQuery);
} else {
t = window.setTimeout(jquery_ready, 100);
}
}
t = window.setTimeout(jquery_ready, 100);
На самом деле мне может понадобиться использовать код более одного раза на странице, код, который не знает о другом коде, поэтому даже это, вероятно, не сработает, если я не переименую каждый jquery_ready в нечто вроде jquery_ready_guid, jquery_ready_otherguid и т.д..
Разъяснение
Просто так ясно, я помещаю include в JavaScript (<script type="text/javascript" src="jquery.min.js" />
) на очень низком страницы, перед </body>
. Поэтому я не могу использовать $
.
Ответы
Ответ 1
Твой путь - единственный способ, о котором я знаю, хотя я бы удостоверился, что область обзора немного туже:
(function() {
var runMyCode = function($) {
// jquery-dependent code here
$("#foo").data('bar', true);
};
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
runMyCode(window.jQuery);
} else {
window.setTimeout(timer, 100);
}
};
timer();
})();
Обновление
Здесь немного отложенного загрузчика, который я собрал вместе:
var Namespace = Namespace || { };
Namespace.Deferred = function () {
var functions = [];
var timer = function() {
if (window.jQuery && window.jQuery.ui) {
while (functions.length) {
functions.shift()(window.jQuery);
}
} else {
window.setTimeout(timer, 250);
}
};
timer();
return {
execute: function(onJQueryReady) {
if (window.jQuery && window.jQuery.ui) {
onJQueryReady(window.jQuery);
} else {
functions.push(onJQueryReady);
}
}
};
}();
Что тогда можно было бы использовать так:
Namespace.Deferred.execute(runMyCode);
Ответ 2
Лучший способ, который я нашел, - написать код в функции и вызвать функцию после загрузки jquery:
function RunAfterjQ(){
// Codes that uses jQuery
}
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
RunAfterjQ();
</script>
Обновление:. Для основных страниц вы можете определить массив для ввода функций в главной странице главной страницы:
var afterJQ = [];
а затем в нижней части главной страницы запустите все функции, вложенные в этот массив:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
for(var i = 0; i < afterJQ.length; i++) afterJQ[i]();
</script>
Всюду, где вам нужно использовать javascript, который полагается на jQuery, и до того, как jQuery определен, просто вставьте его в этот массив:
afterJQ.push( function() {
// this code will execute after jQuery is loaded.
});
Ответ 3
Простое использование чистой версии javascript $(document).ready();
:
document.addEventListener("DOMContentLoaded", function(event) {
//you can use jQuery there
});
Ответ 4
Вот способ написать внедренный код, который будет запускаться только после загрузки jQuery (синхронно или асинхронно).
<script>
if ( ! window.deferAfterjQueryLoaded ) {
window.deferAfterjQueryLoaded = [];
Object.defineProperty(window, "$", {
set: function(value) {
window.setTimeout(function() {
$.each(window.deferAfterjQueryLoaded, function(index, fn) {
fn();
});
}, 0);
Object.defineProperty(window, "$", { value: value });
},
configurable: true
});
}
window.deferAfterjQueryLoaded.push(function() {
//... some code that needs to be run
});
</script>
Что это делает:
- Определяет
deferAfterjQueryLoaded
лениво, поэтому вам не нужно вводить это в head
. - Определяет установщик для
window.$
. Когда jQuery загружается, одна из последних вещей, которые он делает, - это присваивание глобальной переменной $
. Это позволяет вам запускать функцию, когда это происходит. - Запланирует запуск отложенных функций как можно скорее после завершения сценария jQuery (
setTimeout(..., 0);
). - Может ли сеттер удалить себя.
Для полной чистоты вы можете также использовать запланированную функцию удаления deferAfterjQueryLoaded
.
Ответ 5
Как насчет:
<script>
window.deferAfterjQueryLoaded = [];
window.deferAfterjQueryLoaded.push(function() {
//... some code that needs to be run
});
// ... further down in the page
window.deferAfterjQueryLoaded.push(function() {
//... some other code to run
});
</script>
<script src="jquery.js" />
<script>
$.each(window.deferAfterjQueryLoaded, function(index, fn) {
fn();
});
</script>
Это работает, потому что каждый script здесь полностью блокируется. Смысл создания массива deferAfterjQueryLoaded
и всех создаваемых функций и нажатия на этот массив происходит первым. Затем jQuery полностью загружается. Затем вы перебираете этот массив и выполняете каждую функцию. Это работает, если скрипты также находятся в отдельных файлах точно так же.
Если вы также хотите, чтобы DOMReady срабатывал, вы можете вложить $(function() {})
внутри одной из ваших функций deferAfterjQueryLoaded, таких как:
window.deferAfterjQueryLoaded.push(function() {
$(function() {
console.log('jquery loaded and the DOM is ready');
});
console.log('jquery loaded');
});
В конечном счете, вы должны действительно реорганизовать свой код, чтобы все было на самом деле внизу, и иметь систему, способствующую этой модели. Намного легче понять все происходящее и более результативно (особенно если у вас есть отдельные скрипты).
Ответ 6
У меня есть эта же проблема, но с тонны файлов я использую headjs для управления загрузкой, это всего лишь 2kb, поэтому на самом деле это не проблема, для меня, в любом случае, для ввода заголовка. Затем ваш код будет,
head.ready(function(){
$...
});
и внизу страницы
head.js('/jquery.min.js');
Ответ 7
Вы должны сделать это в событии document
ready
.
Ответ 8
function jQueryGodot(code)
{
if (window.jQuery)
{
code(window.jQuery);
}
else
{
if (!window.$)
{
window.$ = { codes: [] };
window.watch('$', function(p, defered, jQuery) {
jQuery.each(defered.codes, function(i, code) {
code(jQuery);
});
return jQuery;
});
}
window.$.codes.push(code);
}
}
jQueryGodot(function($) {
$('div').html('Will always work!');
})
Рабочий пример в JSFiddle.
Код, переданный функции jQueryGodot, всегда будет выполняться независимо от того, вызывается ли он до или после загрузки jQuery.
Решение полагается на Object.watch, для которого требуется этот polyfill (660 байт) в большинстве браузеров: https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66
Ответ 9
Вы можете отложить все вызовы, такие как jQuery (function() {...}) без цикл setTimeout: https://jsfiddle.net/rL1f451q/3/
Он собирает каждый вызов jQuery (...) в массив до тех пор, пока jQuery не будет определен, тогда второй код выполнит их, когда доступен jQuery.
Поместите это в голову или начало тела:
<!-- jQuery defer code body: deferring jQuery calls until jQuery is loaded -->
<script>
window.jQueryQ = window.jQueryQ || [];
window.$ = window.jQuery = function(){
window.jQueryQ.push(arguments);
}
</script>
<!-- end: jQuery defer code body -->
И это в самом конце тела после jQuery script:
<!-- jQuery deferring code footer: add this to the end of body and after the jQuery code -->
<script>
jQuery(function(){
jQuery.each(window.jQueryQ||[],function(i,a){
// to understand why setTimeout 0 is useful, see: https://www.youtube.com/watch?v=8aGhZQkoFbQ, tldr: having a lot of calls wont freeze the website
setTimeout(function(){
jQuery.apply(this,a);
},0);
});
});
</script>
<!-- end: jQuery deferring code footer -->
Ответ 10
Я написал простой код JS для обработки таких случаев: https://github.com/Yorkii/wait-for
Тогда вы можете использовать это так
waitFor('jQuery', function () {
//jQuery is loaded
jQuery('body').addClass('done');
});
Вы даже можете подождать несколько библиотек
waitFor(['jQuery', 'MyAppClass'], function () {
//Both libs are loaded
});