Является ли обратный вызов в getScript () jQuery ненадежным или я что-то делаю не так? - PullRequest
20 голосов
/ 15 июля 2009

Я использую следующий бит скрипта для загрузки другого:

$.getScript("CAGScript.js", function () {
    try {
        CAGinit();
    } catch(err) {
        console.log(err);
    }
});

Идея состоит в том, что $ .getScript загружает скрипт, а затем выполняет обратный вызов, когда это будет сделано. CAGInit() - это функция, которая живет в CAGScript.js.

Проблема в том, что примерно половину времени CAGInit() не срабатывает (в любом браузере). Вход в консоль Firebug сообщает, что он не определен. В остальное время работает отлично.

У кого-нибудь есть идеи, что я делаю не так?

Спасибо.

Ответы [ 11 ]

23 голосов
/ 24 апреля 2011

Я заметил ту же проблему с FF 3.6.

Решением является синхронная загрузка скрипта.

Как упомянуто в документации jQuery , getScript является сокращением для:

$.ajax({
  url: url,
  dataType: 'script',
  success: success
});

Все работает нормально, если я использую следующее вместо getScript:

$.ajax({
  url: url,
  dataType: 'script',
  success: success,
  async: false
});
20 голосов
/ 28 марта 2012

Я просто хотел поделиться своим мнением по этому вопросу. Обратный вызов не сработает, если в загружаемом коде будет ошибка и (по крайней мере, в Chrome с jQuery 1.7.1) ошибка будет проглочена. Я обнаружил, что у меня была случайная фигурная скобка от автозаполнения в коде, который я загружал, и функция обратного вызова не сработала. Непостоянное поведение здесь может быть вызвано изменением загруженного кода между тестами.

10 голосов
/ 15 июля 2009

Если файл хранится в том же домене, то jQuery будет использовать XHR для извлечения его содержимого, а затем глобально «оценит» его. Это должно работать нормально, но если у вас возникли проблемы, я бы предложил использовать альтернативный метод внедрения тега скрипта. К сожалению, 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);

Было бы лучше абстрагировать это от функции; Выше приведен только пример ...

9 голосов
/ 15 января 2010

Просто была такая же проблема на firefox, решил с небольшим взломом.

Применение к вашему примеру:

$.getScript("CAGScript.js", function (xhr) {
    try {
        CAGinit();
    } catch(err) {
        eval(xhr);
        CAGinit();
    }
});

По существу, принуждение к оценке ответа XHR, если оно не может сделать это само.

3 голосов
/ 06 ноября 2013

Чтобы убедиться, что CAGScript.js загружен и выполнен перед вызовом функции CAGinit, самый верный способ - вызвать функцию внутри CAGScript.js.

CAGScript.js:



    ...
    /*
    your code
    */
    function CAGinit(){
    ...
    }
    ...
    /* last line */
    CAGinit();

и затем в вашем главном файле просто вызовите getScript ():

 

    $.getScript("CAGScript.js");

3 голосов
/ 19 июля 2011

Я тоже немного понял эту проблему в Chrome. jQuery иногда вызывает успешный обратный вызов, как будто все в порядке, но скрипт не был загружен должным образом. В нашем случае решение состояло в том, чтобы просто изменить доверие к jQuery:

<script>
    $.getScript("helpers.js", function () {
        // use helpers....or: EXPLODE (wheeeee!)
        helpers.doSomething();
    });
</script>

Чтобы доверять браузеру:

<script src="helpers.js"></script>
<script>
    helpers.doSomething();
</script>

Я снова и снова нахожу, что "меньше jQuery == меньше крайних случаев == меньше ошибок". И обычно более читаемый код тоже!

1 голос
/ 30 сентября 2010

Да, я также обнаружил, что getScript ненадежен в FireFox, вызывая обратный вызов до того, как скрипт был загружен и / или выполнен. (Использование JQuery 1.41 и FireFox 3.6. Кажется, проблема не затрагивает IE, Chrome или Opera.)

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

Предложение RaYell не работает, так как getScript сообщит об успехе, даже если скрипт еще не был оценен. Предложение Питера в большинстве случаев приводит к двойной оценке кода, что неэффективно и может привести к ошибкам.

Эта альтернатива работает там, где getScript не работает. Обратите внимание, что кажется, что он добавляет элемент SCRIPT DOM, тогда как getScript делает XHR.

http://www.diveintojavascript.com/projects/sidjs-load-javascript-and-stylesheets-on-demand

0 голосов
/ 13 июля 2017

Мой путь

setTimeout(function(){ 
  $.getScript( "CAGScript.js");
  }, 
2000);

С этой же проблемой мы сталкиваемся в angular, когда мы хотим обновить данные в $ scope, и она решается с помощью $ timeout таким же образом в angular ...

0 голосов
/ 08 апреля 2016

Похоже, что jQuery теперь отлично справляется с междоменными и однотипными запросами. Для междоменных запросов, он добавит тег сценария и подпишется на события error и load и соответственно вызовет ваши обработанные и ответные вызовы error, это ошибка только в случае сбоя запроса, ошибки при оценке сценария все равно будут считаться успешными, поскольку запрос касается. Для того же источника, он выполнит XHR-запрос, а затем сделает globalEval, и, как только он будет сделан, вызовет ваш обратный вызов done, если что-то не получится в процессе, он вызовет ваш обратный вызов ошибки.

Использование XHR имеет несколько проблем, оно ломает отладчик, исходные карты и основывается на globalEval, который имеет проблемы с ContentSecurityPolicy. Для этой согласованности мы просто добавляем тег сценария при загрузке сценариев.

var scriptElement = $("<script>").prop({src: url, async: true}); scriptElement.one('load', ()=> ...); scriptElement.one('error', (evt)=> ...); document.head.appendChild(scriptElement[0]);

Если вы хотите сделать это без jQuery, найдите динамически импортируемые скрипты в этой статье

Надеюсь, это поможет.

0 голосов
/ 28 февраля 2013

Я хотел, чтобы что-то похожее на auto_load в PHP было реализовано в JS, типичное решение - использовать try-catch для всех функций ... когда функция отсутствует, мы переходим к загрузке ее библиотеки Мое решение взято из решения Питера следующим образом:

function CheckUserPW(username,password){
    try{
       loginCheckUserPW(username,password);
    } catch(err) {
        $.getScript('login.js', function(xhr){ 
            eval(xhr);
            loginCheckUserPW(username,password);
        });
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...