Могу ли я использовать jquery getScript () без обратного вызова? - PullRequest
11 голосов
/ 06 ноября 2011

Мне нужно использовать функцию javascript из внешнего файла js внутри другого файла js.В основном это код, который я пробовал:

$.getScript('js/myHelperFile.js');
myHelperFunction();

Это не работает - я получаю сообщение об ошибке «myHelperFunction не определено».

Однако этот код работает:

$.getScript('js/myHelperFile.js', function(){myHelperFunction();});

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

Ответы [ 4 ]

29 голосов
/ 06 ноября 2011

Выполнение этого «первым способом» в настоящее время * невозможно при jQuery.getScript, поскольку оно поддерживает только асинхронные операции и, следовательно, возвращается сразу после вызова.

Так как он возвращается до того, как ваш скрипт был загружен, когда скрипт пытается вызвать myHelperFunction(), myHelperFunction равен undefined и вызывает эту ошибку.

* См. Обновление внизу этого ответа для многообещающего нового метода, который в конечном итоге позволит вам написать код, который почти работает как ваш желаемый стиль.

Вы можете сделать это, используя jQuery.ajax с настройкой async, установленной на false, с кодом, похожим на этот:

$.ajax({
  url: 'js/myHelperFile.js',
  async: false,
  dataType: "script",
});

myHelperFunction();

Но как документация гласит:

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

Это очень плохо . Если сервер, предоставляющий myHelperFile.js, медленно реагирует в любое время (что произойдет в какой-то момент), страница перестанет отвечать до тех пор, пока запрос не завершится или не истечет время ожидания.

Было бы гораздо лучше использовать стиль обратного вызова, который широко используется в jQuery.

$.getScript('js/myHelperFile.js', function () {
   myHelperFunction();
});

Вам также не нужно использовать анонимную функцию, вы можете поместить свой код в именованную функцию:

function doStuffWithHelper() {
   myHelperFunction();
}

$.getScript('js/myHelperFile.js', doStuffWithHelper);

Если вам нужно загрузить более одной зависимости перед вызовом myHelperFunction, это не сработает, если вы не настроите какую-либо систему для определения, все ли зависимости загружены перед выполнением кода. Затем вы можете установить обработчик обратного вызова для всех вызовов .getScript, чтобы проверить, что все ваши зависимости загружены перед выполнением вашего кода.

var loadedScripts = {
    myHelperFile: false,
    anotherHelperFile: false
};

function doStuffWithHelper() {
    // check to see if all our scripts are loaded
    var prop;
    for (prop in loadedScripts) {
        if (loadedScripts.hasOwnProperty(prop)) {
            if (loadedScripts[prop] === false) {
                return; // not everything is loaded wait more
            }
        }
    }

    myHelperFunction();
}

$.getScript('js/myHelperFile.js', function () {
    loadedScripts.myHelperFile = true;
    doStuffWithHelper();
});
$.getScript('js/anotherHelperFile.js', function () {
    loadedScripts.anotherHelperFile = true;
    doStuffWithHelper();
});

Как видите, такой подход быстро запутывается и становится недостижимым.

Если вам нужно загрузить несколько зависимостей, вам, вероятно, лучше использовать загрузчик сценариев, такой как yepnope.js , чтобы сделать это.

yepnope( {
        load : [ 'js/myHelperFile.js', 'js/anotherHelperFile.js' ],
        complete: function () {
            var foo;
            foo = myHelperFunction();
            foo = anotherHelperFunction(foo);
            // do something with foo
        }
} );

Yepnope использует обратные вызовы, как и .getScript, поэтому вы не можете использовать последовательный стиль, который вы хотели придерживаться. Это хороший компромисс, потому что выполнение нескольких синхронных вызовов jQuery.ajax подряд просто усугубит проблемы методов.


Обновление 2013-12-08

Версия jQuery 1.5 предоставляет еще один чистый способ сделать jQuery. Начиная с 1.5 все AJAX-запросы возвращают отложенный объект , чтобы вы могли сделать это:

$.getScript('js/myHelperFile.js').done(function () {
   myHelperFunction();
});

Будучи асинхронным запросом, он, конечно, требует обратного вызова. Использование Deferreds, однако, имеет огромное преимущество перед традиционной системой обратного вызова, используя $. When () , вы можете легко расширить это для загрузки нескольких обязательных сценариев без вашей собственной сложной системы отслеживания:

$.when($.getScript('js/myHelperFile.js'), $.getScript('js/anotherHelperFile.js')).done(function () {
  var foo;
  foo = myHelperFunction();
  foo = anotherHelperFunction(foo);
  // do something with foo
});

Это будет загружать оба сценария одновременно и выполнять обратный вызов только после того, как они оба были загружены, очень как в примере с Yepnope выше.


Обновление 2014-03-30

Я недавно прочитал статью , в которой я узнал о новой функции JavaScript, которая в будущем может позволить использовать код процедурного вида, который пока еще не асинхронен, который вы хотели использовать! Асинхронные функции будет использовать ключевое слово await, чтобы приостановить выполнение функции async до завершения асинхронной операции. Плохая новость заключается в том, что в настоящее время планируется включить его в ES7, две версии ECMAScript.

await полагается на асинхронную функцию, которую вы ожидаете при возврате Promise . Я не уверен, как поведут себя реализации браузера, если им потребуется настоящий объект ES6 Promise или будет достаточно других реализаций обещаний, подобных той, которую jQuery возвращает из вызовов AJAX. Если требуется обещание ES6, вам нужно обернуть jQuery.getScript функцией, которая возвращает обещание:

"use strict";
var getScript = function (url) {
  return new Promise(function(resolve, reject) {
    jQuery.getScript(url).done(function (script) {
      resolve(script);
    });
  });
};

Затем вы можете использовать его для загрузки и await, прежде чем продолжить:

(async function () {
  await getScript('js/myHelperFile.js');
  myHelperFunction();
}());

Если вы действительно решили писать в этом стиле сегодня, вы можете использовать asyc и await, а затем Traceur , чтобы преобразовать ваш код в код, который будет работать в текущих браузерах. Дополнительным преимуществом этого является то, что вы также можете использовать множество других полезных новых функций ES6 .

2 голосов
/ 06 ноября 2011

$. GetScript, и на самом деле все функции jQuery, связанные с HTTP OP, являются неблокирующими вызовами по умолчанию.То есть код не зависает, когда операция завершается.Это означает, что ваш приведенный выше код наверняка завершится сбоем, потому что нет никакого способа, которым $ .getScript загрузит скрипт до того, как будет запущена строка, выполняющая метод.Вот почему функции обратного вызова принимаются в качестве параметров.

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

var HelperFileLoaded = false; 
$.getScript('js/myHelperFile.js', function() { HelperFileLoaded = true; });

// ...

function btnSaveClick() {
    if(!HelperFileLoaded) return;
    myHelperFunction(); 
}

Предложение BenM возможно, но если вы не сделаете только один вызов myHelperFunction, оно не будетработать как решение, потому что не будет никакой гарантии, что скрипт будет загружен до того, как будут запущены любые другие методы, вызывающие myHelperFunction.

2 голосов
/ 06 ноября 2011

Использование функции getScript() само по себе, я не думаю, что вы можете.Проблема в том, что скрипт загружается с использованием AJAX (действительно, getScript - это просто сокращение для специальной функции $.ajax()), и когда браузер пытается выполнить функцию на следующей строке, возможно, сервер еще не сделалвернул файл.

Если вы не хотите использовать функцию обратного вызова, вам нужно будет использовать функцию jQuery $.ajax() в ее первоначальном виде (и забыть о getScript()) и установить передачукак синхронно .Таким образом, вы можете быть уверены, что скрипт будет загружен до выполнения вашего кода:

$.ajax({
    url: url,
    dataType: "script",
    async: false
});
0 голосов
/ 22 ноября 2013

Ваш первый работает нормально, если вы используете JSONP, я делаю это часто.

...