Подтвердить что ты не робот

Обработка кода, который опирается на 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>. Поэтому я не могу использовать $.

4b9b3361

Ответ 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>

Что это делает:

  1. Определяет deferAfterjQueryLoaded лениво, поэтому вам не нужно вводить это в head.
  2. Определяет установщик для window.$. Когда jQuery загружается, одна из последних вещей, которые он делает, - это присваивание глобальной переменной $. Это позволяет вам запускать функцию, когда это происходит.
  3. Запланирует запуск отложенных функций как можно скорее после завершения сценария jQuery (setTimeout(..., 0);).
  4. Может ли сеттер удалить себя.

Для полной чистоты вы можете также использовать запланированную функцию удаления 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
});