我正在编写一个需要广泛使用getScript的引擎。为了便于使用,我已将其推入自己的功能,但现在我需要确保函数本身是同步的。不幸的是,我似乎无法让getScript等到它加载的脚本在继续之前实际完成加载。我甚至尝试在调用之前将jQuery的ajax asynch属性设置为false。我正在考虑使用jQuery的when / done协议,但我似乎无法理解将其置于函数内并使函数本身同步的逻辑。非常感谢任何帮助!
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;
}
}
答案 0 :(得分:24)
这对我有用,可能对你有帮助。
$.ajax({
async: false,
url: "jui/js/jquery-ui-1.8.20.min.js",
dataType: "script"
});
基本上,我只是绕过了速记符号并添加到async: false
答案 1 :(得分:11)
正如我所说,使用promise对象链接Ajax调用相对容易。现在,它没有看到为什么脚本必须一个接一个地加载,但你有理由这样做。
首先,如果您只使用不同的参数调用相同的函数,我将删除switch
语句。例如。您可以将所有脚本URL放在地图中:
var scripts = {
'#FFF': '...',
'#000': '...'
// etc.
};
您可以通过简单地从传递给.then
[docs]的回调中返回另一个承诺来链接承诺。您需要做的就是从承诺或延期对象开始:
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
循环。
答案 2 :(得分:5)
你知道$.getScript
accepts一个在加载脚本后同步调用的回调函数吗?
示例:
$.getScript(url,function(){
//do after loading script
});
我还有两个解决方案:pure js一个,一个multiple js load。
答案 3 :(得分: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
});
答案 4 :(得分: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);
};
答案 5 :(得分:0)
@Felix Kling的回答是一个不错的开始。但是,我发现如果要“功能化”,返回的.done()
末尾的附加.getScripts()
会有一个小问题。您需要循环中链式.getScript()
迭代的最后一个承诺。这是他的解决方案的修改版(谢谢您,顺便说一句)。
(function ($) {
var fetched = new function () {
this.scripts = [];
this.set = [];
this.exists = function (url) {
var exists = false;
$.each(this.set, function (index, value) {
if ((url || '') === value) {
exists = true;
return false;
}
});
return exists;
};
this.buildScriptList = function () {
var that = this;
that.set = [];
$('script').each(function () {
var src = $(this).attr('src') || false;
if (src) {
that.set.push(src);
}
});
$.merge(this.set, this.scripts);
return this;
};
},
getScript = $.getScript;
$.getScript = function () {
var url = arguments[0] || '';
if (fetched.buildScriptList().exists(url)) {
return $.Deferred().resolve();
}
return getScript
.apply($, arguments)
.done(function () {
fetched.scripts.push(url);
});
};
$.extend({
getScripts: function (urls, cache) {
if (typeof urls === 'undefined') {
throw new Error('Invalid URL(s) given.');
}
var deferred = $.Deferred(),
promise = deferred.promise(),
last = $.Deferred().resolve();
if (!$.isArray(urls)) {
urls = [urls];
}
$.each(urls, function (index) {
promise = promise.then(function () {
last = $.getScript(urls[index]);
return last;
});
});
if (Boolean(cache || false) && !Boolean($.ajaxSetup().cache || false)) {
$.ajaxSetup({cache: true});
promise.done(function () {
$.ajaxSetup({cache: false});
});
}
deferred.resolve();
return last;
}
});
})($);
您可以忽略获取的功能(我实现了该功能以减少潜在的冗余调用-这就是我劫持.getScript()
的原因),并查看变量last
在.getScripts()
方法内的位置。它默认为解析的延迟对象,因此,如果urls数组为空,则将其传递给返回的结果,以将外部.done()
附加到该结果。否则,将不可避免地为链式.getScript()
调用分配最后一个诺言对象,从而确保一切都将从函数外部保持同步。
如果您先解决了最初创建的延迟对象,然后再将其返回给调用者(这是根据jQuery's official documentation应该执行的操作),则无法将其恢复。
function loadStuff(data) {
var version = {
'accounting': '1.2.3',
'vue': '1.2.3',
'vueChart': '1.2.3'
};
$.getScripts([
'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/' + version.accounting + '/accounting.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue/' + version.vue + '/vue.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue-chartjs/' + version.vueChart + '/vue-chartjs.min.js'
], true)
.done(function () {
// do stuff
})
.fail(function () {
throw new Error('There was a problem loading dependencies.');
});
}
答案 6 :(得分:-1)
只需创建一个脚本节点,将其src属性设置为您要加载的JS,然后将其附加到头部:
var myScript = document.createElement('script');
myScript.src = "thesource.js";
document.head.appendChild(myScript);
答案 7 :(得分:-1)
这就是我的工作
function loadJsFile(filename) {
$.ajaxSetup({
cache: true
});
var dloadJs = new $.Deferred();
$.when(dloadJs).done(function () {
$.ajaxSetup({
cache: false
});
});
dloadJs.resolve(
$.getScript(filename, function () { })
);
}