Можно ли использовать jquery getScript() без обратного вызова?

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

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

Это не работает. Я получаю сообщение об ошибке "myHelperFunction не определен".

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

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

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

Ответ 1

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

Так как он возвращается до того, как ваш script был загружен, когда script пытается вызвать 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 release предоставляет другой чистый способ 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 или если будут реализованы другие реализации promises, подобные тому, который один из jQuery возвращает из вызовов AJAX. Если требуется ES6 Promise, вам необходимо обернуть jQuery.getScript функцией, которая возвращает Promise:

"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

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

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

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

Ответ 3

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

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

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

// ...

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

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

Ответ 4

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