Выполнение этого «первым способом» в настоящее время * невозможно при 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 .