When I alert my array “markerArray” outside the geocoder-function it says it’s undefined.
Can’t figure out why? Is there a way to get the values from the array outside the function?
var markerArray = new Array();
for(var i in opts.markers)
{
address = opts.markers[i].address;
//alert(opts.markers[i].icon);
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: address }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
}
}
markerArray[i] = marker;
});
}
alert(markerArray[0].position);
I suspect it’s not
markerArraythat it’s complaining about, butmarkerArray[0]that’s undefined.You’re calling an asynchronous API using functions you create in a loop. Those functions are closures. They each have an enduring reference to the
ivariable, not a copy of the value as it was when the function was defined. So all of the functions use the lastivalue from the loop, because none of them runs until the loop is over. So if the last valueihas in the loop is5, say, then all of the functions will use5.Also, you’re then doing your
alerttoo soon, before any of the callbacks has a chance to run. You’ll need to do whatever final processing you need to do in one of the callbacks (you can use a counter to know when they’ve all happened).You can fix both the
markerArrayproblem and the prematurealertlike this:Now, the callbacks are closures over the
indexargument you pass into thebuildCallbackfunction, instead of theivariable in your main loop. We do the alert when we’re done with all the callbacks, which we know because of thecallcounter(see note below if your “race condition” radar is going off).All of this is because of the way closures work. They’re not complicated (in fact, I wrote a blog post about them called Closures are not complicated), but there are some things you need to firmly understand to “get” why they do what they do.
Separately: You’re using
for..into loop throughopts.markers, which I suspect is an array. If it is, then that code has issues you need to solve.for..inis not for looping through the indexes of an array, it’s for looping through the property names of an object. More here. You either need to add some checks to yourfor..inloop, or just use a boring old-fashionedforloop.Re the
counter: To anyone used to multi-threaded programming, my simple “increment it when scheduling, decrement it when processing” logic looks like it sets up a race condition (what if the first one gets called back before the second one is scheduled?). But it’s not a race condition in JavaScript on browsers, because JavaScript on browsers is single-threaded (or if you use web workers, kind of cooperatively multi-threaded). There is no pre-emptive multi-threading here. None of the callbacks will ever be called until they have all been scheduled.Off-topic: Although
var markerArray = new Array();works just fine, I’d recommendvar markerArray = [];instead. It’s shorter; for various reasons the implementation can optimize it a bit more (not that it really matters); and there’s no possibility that someone has shadowed theArraysymbol. Similarly, any time you want just a blank object, use{}instead ofnew Object().