jQuery.get
is asynchronous. You are iterating inside the callback for an AJAX call, so that gets executed whenever the AJAX call is completed.
AJAX callbacks, setTimeout
and setInterval
are some asynchronous Javascript functions. Some threads you might find useful:
Edit: Yes, the function call ends before any of the callback stuff happens. Basically the execution of your JS will be linear, placing functions on a call stack whenever they are called. On the call-stack they are executed one-by-one, line-by-line. However, when one of those lines calls an asynchronous function (like a setTimeout
or AJAX), the current execution places the async function on the call-stack and immediately returns to complete itself. So something like:
function myFunc(){
console.log('a');
setTimeout(function(){
console.log('b');
},0)
console.log('c');
}
myFunc();
would always log:
a
c
b
...even though the setTimeout
is 0.
So, in your case what must be happening is that you are assigning the AJAX-received data to svgIcons[icon_name]
inside the async callback (obviously), while the rest of your code which uses the object svgIcons
is in the sequential/normal execution. You either have to move the code that uses the object inside the async callback, or use promises (basically promises are functions that are executed after an async call is completed).
2nd Edit: So, the reason you are not able to set svgIcons[icon_name]
inside the callback is related to the things I was mentioning in my comment. When synchronous functions are called, they are placed on top of the current stack and executed right away, before returning to the calling function. So if you called a sync function inside a loop:
function outer(){
function inner(){
console.log(i);
}
for(var i=0;i<3;i++)
inner();
}
outer();
the synchronous inner
function would be executed right away inside each loop, and would have access to the current value of i
, so it would output 0
, 1
, 2
(as expected).
If however, inner
was asynchronous, e.g
function outer(){
for (var i=0;i<3;i++)
setTimeout(function(){console.log(i)},0);
}
Then you would get 3
, 3
, 3
as the output!
This is because the loop has already finished, including the final i++
.
So now I think you can see the problem with your code. Upto calling jQuery.get
you have access to the current value of icon_name
, but once we are inside that asynchronous callback, the current value disappears and is replaced by the last value for it, because the loop already completed before any of the callbacks were executed.
Try something like this:
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()
This uses the forEach
method, which is native to arrays (MDN reference). Inside the function passed to forEach
, the first argument is always the current element of the array (which I named as prop
). So there is no messy loop or i
, and every executing function has access to its own prop
property.
Then, inside the AJAX callback, I assign the current prop
to the data received, and then loop through all the properties to check if the svgIcons
object has received the properties. So fullyLoaded
will only evaluate to true once all the callbacks have been executed and the global svgIcons
has received all the properties and data. Hence, you can now call the function that uses the object.
Hope this helps, feel free to ask further or let me know if the console throws errors.