我有一些PHP的经验,但我开始使用javascript和jquery。我正在研究我的第一个项目。我认为脚本编写脚本,这与PHP之间几乎没有区别。好吧,我错了。我第一次看到代码中第一个执行的东西最后一次!
请看看这个函数是什么意思是获取svg并将它们存储在json对象中以便以后用作内联svg
var svgIcons = { "arrow_left": "", "arrow_right":"", } //json object with empty values
this.getIcons = function() {
for (var icon_name in svgIcons) {
if (svgIcons.hasOwnProperty(icon_name)) {
var url=PHP.plugin_url+'/includes/icons/'+icon_name+'.svg';
jQuery.get(url, function(data) {
svgIcons[icon_name]=data;
console.log('iterating');
console.log(svgIcons[icon_name]); //outputs svg
});
}
}
console.log('this should be after iteration');
console.log(svgIcons["arrow_left"]); //empty
}
this.getIcons(); //called at object initialization
但输出是:
this should be after iteration
iterating
#document (and svg inside it)
iterating
#document (and svg inside it)
这种订单变更的原因是什么?是get()函数吗?我该如何避免这种情况?
答案 0 :(得分:1)
jQuery.get
是异步的。您正在回调AJAX调用的回调内部,以便在AJAX调用完成时执行。
AJAX回调,setTimeout
和setInterval
是一些异步Javascript函数。您可能会发现一些有用的线程:
编辑:是的,函数调用在任何回调内容发生之前结束。基本上,JS的执行是线性的,只要调用它们就将函数放在调用堆栈上。在调用堆栈上,它们逐行逐行执行。但是,当其中一行调用异步函数(如setTimeout
或AJAX)时,当前执行会将异步函数放在调用堆栈上并立即返回以完成自身。如下所示:
function myFunc(){
console.log('a');
setTimeout(function(){
console.log('b');
},0)
console.log('c');
}
myFunc();
总是会记录:
a
c
b
...即使setTimeout
为0。
因此,在您的情况下,必须发生的是您将异步回调中的AJAX接收数据分配给svgIcons[icon_name]
(显然),而使用对象{{1}的代码的其余部分在顺序/正常执行中。您要么必须移动在异步回调中使用该对象的代码,要么使用promises(基本上承诺是在异步调用完成后执行的函数)。
第二次修改:因此,您无法在回调中设置svgIcons
的原因与我在评论中提到的内容有关。当调用同步函数时,它们被放置在当前堆栈的顶部并立即执行,在返回调用函数之前。因此,如果您在循环中调用 sync 函数:
svgIcons[icon_name]
同步function outer(){
function inner(){
console.log(i);
}
for(var i=0;i<3;i++)
inner();
}
outer();
函数将立即执行 in 每个循环,并且可以访问当前值inner
,因此它将输出{{1} },i
,0
(按预期方式)。
但是,如果1
是异步的,例如
2
然后你会得到inner
, function outer(){
for (var i=0;i<3;i++)
setTimeout(function(){console.log(i)},0);
}
,3
作为输出!
这是因为循环已经完成,包括最终的3
。
所以现在我认为您可以看到代码的问题。最多调用3
您可以访问{em>当前的i++
值,但是一旦我们进入异步回调,当前值就会消失,并被最后一个值替换掉,因为在执行任何回调之前循环已经完成。
尝试这样的事情:
jQuery.get
这使用icon_name
方法,该方法是数组(MDN reference)的原生方法。在传递给var svgIcons = {}
var props = ["arrow_left","arrow_right"];
this.getIcons = function() {
props.forEach(function(prop){
var url=PHP.plugin_url+'/includes/icons/'+prop+'.svg';
jQuery.get(url, function(data) {
svgIcons[prop]=data;
var fullyLoaded = false;
for(var i=0;i<props.length;i++) {
if(!svgIcons.hasOwnProperty(props[i])){
fullyLoaded = false;
break;
}
else fullyLoaded = true;
} // end for loop
if(fullyLoaded)
callMyFunctionWhereIUseSvgIconsData();
}); //end jQuery.get()
});//end forEach
}
this.getIcons()
的函数内部,第一个参数始终是数组的当前元素(我将其命名为forEach
)。因此没有杂乱的循环或forEach
,并且每个执行的函数都可以访问自己的prop
属性。
然后,在 AJAX回调中,我将当前i
分配给收到的数据,然后遍历所有属性以检查prop
对象是否已收到属性。因此,只有在执行了所有回调并且全局prop
已收到所有属性和数据后,svgIcons
才会评估为true。因此,您可以现在调用使用该对象的函数。
希望这有帮助,请随时进一步询问或告诉我控制台是否会出错。
答案 1 :(得分:0)
任何ajax调用都是异步的,因此可以在进行ajax调用时运行它。如果您想在完成所有通话后拨打电话,请尝试以下操作:
var svgIcons = { "arrow_left": "", "arrow_right":"", } //json object with empty values
var executing = 0;
this.getIcons = function() {
for (var icon_name in svgIcons) {
//store that this call has started
exectuing = executing + 1;
if (svgIcons.hasOwnProperty(icon_name)) {
var url=PHP.plugin_url+'/includes/icons/'+icon_name+'.svg';
console.log('this will run as you were expecting');
//this ajax call is then started and moves to next iteration
jQuery.get(url, function(data) {
//This is run after the ajax call has returned a response, not in the order of the code
svgIcons[icon_name]=data;
console.log('iterating');
console.log(svgIcons[icon_name]); //outputs svg
//if you want to call a function after evey call is comeplete then ignore the 'executing' part and just call the function here.
//decrement value as this call has finished
executing = executing - 1;
//if all have finished then call the function we want
if(executing === 0){
executeAfter();
}
});
}
}
console.log('this should be after iteration');
console.log(svgIcons["arrow_left"]); //empty
}
this.executeAfter(){
//This will be exectued after all of you ajax calls are complete.
}
this.getIcons(); //called at object initialization