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