Handling code which relies on jQuery before jQuery is loaded

javascript jquery

16238 просмотра

10 ответа

I'd like to follow the general guideline of putting all JavaScript at the very bottom of the page, to speed up loading time and also to take care of some pesky issues with conflicting jQuery versions in a web app (Django).

However, every so often I have some code, code which depends on jQuery, but which must be further up on the page (basically the code can't be moved to the bottom).

I'm wondering if there's an easy way to code this so that even though jQuery is not yet defined the code works when jQuery is defined.

The following seems, I have to say, like overkill but I don't know of another way to do it:

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_ справ , jquery_ready_ otherguid и так далее.

осветление

Чтобы это было понятно, я помещаю include в JavaScript ( <script type="text/javascript" src="jquery.min.js" />) в самом низу страницы, прямо перед </body>. Так что я не могу использовать $.

Автор: Jordan Reiter Источник Размещён: 11.07.2019 10:44

Ответы (10)


17 плюса

Решение

Твой путь - единственный способ, о котором я знаю, хотя я бы позаботился о том, чтобы границы были немного теснее:

(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);
Автор: Rich O'Kelly Размещён: 28.11.2011 03:59

17 плюса

Лучший способ, который я нашел, - написать код в функции и вызвать функцию после загрузки 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.
 });
Автор: Ashkan Mobayen Khiabani Размещён: 03.09.2014 04:19

16 плюса

Простое использование чистой версии JavaScript $(document).ready();:

document.addEventListener("DOMContentLoaded", function(event) { 
    //you can use jQuery there
});
Автор: bodolsog Размещён: 14.04.2017 06:38

10 плюса

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

Автор: radiaph Размещён: 23.03.2015 06:12

7 плюса

Как насчет:

<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>

Это работает, потому что каждый скрипт здесь полностью блокируется. Значение создания deferAfterjQueryLoadedмассива и всех функций, которые создаются и передаются в этот массив, выполняются первыми. Тогда jQuery полностью загружается. Затем вы перебираете этот массив и выполняете каждую функцию. Это работает, если сценарии также находятся в отдельных файлах одинаково.

Если вы также хотите, чтобы DOMReady запускал, вы можете вложить $(function() {})внутрь одной из ваших функций deferAfterjQueryLoaded, например:

window.deferAfterjQueryLoaded.push(function() {
    $(function() {
        console.log('jquery loaded and the DOM is ready');
    });
    console.log('jquery loaded');
});

В конечном счете, вы должны действительно реорганизовать свой код, чтобы все было на самом деле внизу, и иметь систему, способствующую этой модели. Гораздо проще понять все происходящее и сделать его более производительным (особенно если у вас есть отдельные сценарии).

Автор: Parris Размещён: 18.03.2015 08:12

4 плюса

У меня та же проблема, но с кучей файлов я использую headjs для управления загрузкой, это всего лишь 2 КБ, так что в любом случае для меня не проблема вставить заголовок. Ваш код становится

head.ready(function(){
  $...
});

и внизу страницы,

head.js('/jquery.min.js');
Автор: Andrew Размещён: 28.11.2011 04:00

1 плюс

Вы должны быть в состоянии сделать это на document readyмероприятии.

Автор: Daniel A. White Размещён: 28.11.2011 03:53

1 плюс

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, который требует этого полифилла (минимизировано 660 байт) в большинстве браузеров: https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66

Автор: brother Filip Размещён: 23.03.2015 11:17

1 плюс

Вы можете отложить все вызовы, такие как 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:

<!-- 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 -->
Автор: Viktor Camp Размещён: 21.04.2017 09:07

0 плюса

Я написал простой код 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
});
Автор: Yorki Размещён: 07.06.2019 08:08
Вопросы из категории :
32x32