2013-02-08 325 views
18

我正在编写一个需要相当广泛地使用getScript的引擎。为了便于使用,我将它推入自己的函数中,但现在我需要确保函数本身是同步的。不幸的是,我似乎无法让getScript等待,直到它加载的脚本在继续之前实际上完成加载。我甚至尝试在调用之前将jQuery的ajax asynch属性设置为false。我正在考虑使用jQuery的when/done协议,但似乎无法围绕将它放入函数并使函数本身同步的逻辑。任何帮助将非常感谢!同步使用getScript

function loadScript(script){ 
//Unrelated stuff here!!! 
$.when(
$.getScript(script,function(){ 
    //Unrelated stuff here!!! 
})).done(function(){ 
    //Wait until done, then finish function 
}); 
} 

循环代码(按要求):

for (var i in divlist){ 
     switch($("#"+divlist[i]).css({"background-color"})){ 
      case #FFF: 
      loadScript(scriptlist[0],divlist[i]); 
      break; 
     case #000: 
      loadScript(scriptlist[2],divlist[i]); 
      break; 
     case #333: 
      loadScript(scriptlist[3],divlist[i]); 
      break; 
     case #777: 
      loadScript(scriptlist[4],divlist[i]); 
      break; 
    } 
} 
+1

没有必要做'loadScript'同步。只需返回promise对象形式'$ .getScript'并让调用代码绑定回调。或者为什么你认为它必须是同步的? – 2013-02-09 00:51:24

+0

我正在循环使用for-in循环的div的可变长度数组(根据页面的不同而不同),并对它们执行一系列指令,包括加载脚本。问题是,脚本必须在前一个完成加载和执行后加载。不幸的是,我还没有找到一种合适的方式来“等待”一个对象存在于JavaScript中。区间效果很好,除了它的所有内部都是针对div的for-in循环。 – VashGH 2013-02-09 01:44:17

+0

你是否在每个div上应用相同的命令(我假设这是一个循环)但为每个div加载不同的脚本?你可以发布一些代码吗?使用延迟对象链接Ajax调用很容易。 – 2013-02-09 01:46:40

回答

10

正如我所说,将Ajax调用与承诺对象链接起来相对比较容易。现在,它没有看到为什么脚本必须一个接一个地加载,但你会有一个理由。

首先,虽然我会摆脱switch声明,如果你只是用不同的参数调用相同的函数。例如。通过简单地返回从传递给.then[docs]回调的另一个承诺

var scripts = { 
    '#FFF': '...', 
    '#000': '...' 
    // etc. 
}; 

您可以链的承诺:你可以把所有的脚本网址的映射。所有你需要做的是开始一个承诺或延期对象:

var deferred = new $.Deferred(); 
var promise = deferred.promise(); 

for (var i in divlist) { 
    // we need an immediately invoked function expression to capture 
    // the current value of the iteration 
    (function($element) { 
     // chaining the promises, 
     // by assigning the new promise to the variable 
     // and returning a promise from the callback 
     promise = promise.then(function() { 
      return loadScript(
       scripts[$element.css("background-color")], 
       $element 
      ); 
     }); 
    }($('#' + divlist[i]))); 
} 

promise.done(function() { 
    // optional: Do something after all scripts have been loaded 
}); 

// Resolve the deferred object and trigger the callbacks 
deferred.resolve(); 

loadScript,你简单地返回的承诺从$.getScript返回或通过.done返回的一个:

function loadScript(script_url, $element){ 
    // Unrelated stuff here!!! 

    return $.getScript(script_url).done(function(){ 
     // Unrelated stuff here 
     // do something with $element after the script loaded. 
    }); 
} 

该脚本将所有按循环中的访问顺序调用。请注意,如果divlist是一个数组,您确实应该使用普通的for循环而不是for...in循环。

+0

deferred.resolve()抛出错误(函数不存在)并且代码不按预期执行。 – VashGH 2013-02-09 03:22:26

+0

嗯。在最近的jQuery版本中,延迟/承诺对象发生了一些变化。我更新了这个例子,并希望它现在可以运行。 – 2013-02-09 03:24:55

+0

这个技巧。感谢您不仅解决我的问题,还让我接触到执行链接任务的新方法。这个推迟/承诺的逻辑非常有趣! – VashGH 2013-02-09 03:30:54

-1

只需创建一个脚本节点,它的SRC属性设置为JS要加载然后将其附加到头部:

var myScript = document.createElement('script'); 
myScript.src = "thesource.js"; 
document.head.appendChild(myScript); 
+0

同步运行并确保脚本在执行任何其他代码之前完成加载? – VashGH 2013-02-08 23:39:00

+0

对,脚本加载同步除非你添加异步属性 – 2013-02-08 23:39:50

+1

我可以发誓他们同步加载,但它似乎并非如此,我很抱歉误导你。 – 2013-02-08 23:43:42

3

试试这种方法,用延迟对象创建数组,并使用$ .when和“apply”

var scripts = [ 
    'src/script1.js', 
    'src/script2.js' 
]; 

var queue = scripts.map(function(script) { 
    return $.getScript(script); 
}); 

$.when.apply(null, queue).done(function() { 
    // Wait until done, then finish function 
}); 
+0

我的主要问题是我需要它在一个函数内(因为我使用相同的20行左右的代码),我需要函数本身是同步的。该代码只是给了我一个脚本完成加载时的回调。 getScript已经具有该功能。 – VashGH 2013-02-08 23:53:07

+1

也许你应该看看AMD体系结构,并将requirejs与模块依赖关系一起使用? http://requirejs.org/docs/api.html#modulename – kupriyanenko 2013-02-09 00:04:12

0
var getScript = function(url) { 
    var s = document.createElement('script'); 
    s.async = true; 
    s.src = url; 
    var to = document.getElementsByTagName('script')[0]; 
    to.parentNode.insertBefore(s, to); 
}; 
23

这对我有效,并可能帮助你。

$.ajax({ 
    async: false, 
    url: "jui/js/jquery-ui-1.8.20.min.js", 
    dataType: "script" 
}); 

基本上,我只是绕开速记符号,并在async: false

+2

它为我工作。简单而简单。 – sparrow 2013-11-05 23:05:43

+2

已弃用,不再工作 – njzk2 2013-11-15 21:43:53

+1

它还活着!谢谢! – 2014-11-27 16:01:45

4

添加你知道$.getScriptaccepts是剧本后同步调用回调函数加载?

实施例:

$.getScript(url,function(){ 
//do after loading script 
}); 

我有2级以上的解决方案:一个pure js一个,一个用于multiple js load

-1

这是我做的

function loadJsFile(filename) { 
    $.ajaxSetup({ 
     cache: true 
    }); 

    var dloadJs = new $.Deferred(); 
    $.when(dloadJs).done(function() { 
     $.ajaxSetup({ 
      cache: false 
     }); 
    }); 

    dloadJs.resolve(
     $.getScript(filename, function() { }) 
    ); 
}