Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript callback functions and recursion

This is kind of a brainteaser question, since the code works perfectly fine as-is, it just irritates my aesthetic sense ever so slightly. I'm turning to Stack Overflow because my own brain is failing me right now.

Here's a snippet of code that looks up an address using the Google Maps JS API and places a marker on a map. However, sometimes the initial lookup fails, so I want to repeat the process with a different address.

geocoder.getLatLng(item.mapstring, function(point) {
    if (!point) {
        geocoder.getLatLng(item.backup_mapstring, function(point) {
            if (!point) return;
            map.setCenter(point, 13);
            map.setZoom(7);
            map.addOverlay(new GMarker(point));
        })
        return;
    }
    map.setCenter(point, 13);
    map.setZoom(7);
    map.addOverlay(new GMarker(point));
})

(The second parameter to getLatLng is a callback function.)

Of course you can see that the three lines that center and zoom the map and add the marker are duplicated, once in the primary callback and once in the "fallback callback" (ha ha). Can you find a way to express the whole thing without any redundancy? You earn bonus points, and my adulation, if your solution works for an arbitrary number of backup map strings.

like image 501
lawrence Avatar asked Nov 09 '08 03:11

lawrence


1 Answers

The other answers are good, but here's one more option. This allows you to keep the same form you started with but uses the trick of naming your lambda function so that you can refer to it recursively:

mapstrings = ['mapstring1', 'mapstring2', 'mapstring3'];

geocoder.getLatLng(mapstrings.shift(), function lambda(point) {
   if(point) {
        // success
        map.setCenter(point, 13);
        map.setZoom(7);
        map.addOverlay(new GMarker(point));
    }
    else if(mapstrings.length > 0) {
        // Previous mapstring failed... try next mapstring
        geocoder.getLatLng(mapstrings.shift(), lambda);
    }
    else {
        // Take special action if no mapstring succeeds?
    }
})

The first time the symbol "lambda" is used, it is to introduce it as a new function literal name. The second time it is used, it is a recursive reference.

function literal naming works in Chrome, and I assume it works in most modern browsers, but I haven't tested it and I don't know about older browsers.

like image 164
tway Avatar answered Oct 19 '22 08:10

tway