2011-11-06 126 views
11

我需要从另一个js文件中的外部js文件使用JavaScript函数。这基本上是我试过的代码:我可以在没有回调的情况下使用jquery getScript()吗?

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

这不工作 - 我得到“没有定义myHelperFunction”的错误。

然而,此代码的工作:

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

我特别希望能够做到这一点的第一种方式 - 加载在我的文件的开头的文件,然后使用我从那里需要的任何功能。这是可能的,还是我误解getScript的工作原理?

回答

29

这样做“第一种方式”目前不是*可能与jQuery.getScript,因为它只支持异步操作,因此它被调用后立即返回。

由于在脚本尝试调用myHelperFunction(),myHelperFunction时出现脚本下载之前,它会返回undefined并导致该错误。

*看到这个答案的底部有前途的新方法,最终将让你编写代码,几乎就像你所需的样式更新。

你可以使用jQuery.ajaxasync设置设为false与代码是这样做的:

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

myHelperFunction(); 

documentation状态:

同步请求可能暂时锁定浏览器,在请求处于活动状态时禁用任何操作。

这是一件非常糟糕的事情。如果提供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,所以你不能用你想坚持使用顺序的风格。这是一个很好的折衷,但因为在同一行中执行多个同步调用只会复合该方法的问题。


更新2013年12月8日

jQuery 1.5 release,提供了这样做的另一个纯jQuery的方式。作为1.5,所有的AJAX请求返回Deferred Object,所以你可以这样做:

$.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年3月30日

最近,我读an article让我意识到一个新的JavaScript功能,可能在未来实现那种程序,寻找至今没有异步代码的那你想用! Async Functions将使用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(); 
}()); 

如果你是真的决定今天写这种风格,你可以使用asycawait,然后用Traceur将代码转换成可以在当前浏览器中运行的代码。这样做的附加好处是你也可以使用很多other useful new ES6 features

+0

令人惊讶的全面的答案,做得好! – GregL

+0

+!相当完整的答案。 Howerever,如果你为jQuery加载时为什么要迭代for..in'合成器? –

+0

@ gion_13它允许我从内部返回if(loadedScripts [prop] === false){'退出该函数,以便下列依赖于依赖关系的代码不会运行。如果我使用'$ .each',我可以用'return false'尽早停止循环,但是循环后面的代码会运行,我必须在循环之前设置某种标志,然后在循环之后检查它以防止代码运行。使用'for..in'循环并退出函数更清晰。现在看看它,而不是字典,我会只使用一个计数变量,并将其与全部脚本进行比较。 –

2

单独使用getScript()函数,我认为你不能。问题在于使用AJAX加载脚本(实际上,getScript只是一个特殊的$.ajax()函数的简写),并且当浏览器尝试在下一行执行该函数时,服务器可能尚未返回该文件。

如果你不希望使用一个回调函数,你需要使用jQuery的$.ajax()功能的原始形式(而忽略了getScript()),并设置转移为同步。通过这种方式,你可以肯定的是,该脚本将你的代码的执行之前加载继续:

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

$ .getScript,真的所有HTTP OP相关的jQuery的功能是默认情况下非阻塞调用。也就是说,在操作完成时代码不会挂起。这意味着上面的代码肯定会失败,因为在试图执行方法的行运行之前,$ .getScript将无法加载脚本。这就是回调函数被接受为参数的原因。

但是,你想要做的是可能的。脚本加载后,您应该可以从任何地方调用它。在下载脚本之前避免调用方法的所有必要条件是设置必要的标志。

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

// ... 

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

BenM的建议是可行的,但除非你只想进行一次调用myHelperFunction也不会作为解决方案的工作,因为会有不保证该脚本将之前的任何其他方法调用myHelperFunction有下载被触发。

0

如果您使用JSONP,您的第一个工作正常,我经常这样做。

相关问题