“第一种方式”目前*不可能,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 对象,或者其他承诺的实现,比如从 AJAX 调用返回的一个 jQuery 就足够了。如果需要 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 新特性。