简体   繁体   中英

Titanium and Javascript anonymous function scope

I am trying to call the forwardGeocoder function in titanium, but I am having some issues with retrieving the results, consider the following code :-

x = 0;

Ti.Geolocation.forwardGeocoder(startTextFieldContents, function(evt) {
    var startPin = Ti.Map.createAnnotation({
        longitude   :   evt.longitude,
        latitude    :   evt.latitude,
        pincolor    :   Ti.Map.ANNOTATION_GREEN
    });
    
    var startPinLocation = {
        longitude       : evt.longitude,
        latitude        : evt.latitude
    }
    
    mapview.addAnnotation(startPin);
    x = 1;
});

Ti.API.log('X = ' + x);

If you take a look at X, when I log this out it is ALWAYS equal to 0 even though I am setting it inside my anonymous function as 1, and because this is a function call with an anonymous function as an argument I am struggling to figure out how to retrieve that value and make it available outside the forwardGeocoder.

To resolve this, based on what was said in this post I used the following code:

var completed = 0;
        
        Ti.Geolocation.forwardGeocoder(startTextFieldContents, function(evt) {
            var startPin = Ti.Map.createAnnotation({
                longitude   :   evt.longitude,
                latitude    :   evt.latitude,
                pincolor    :   Ti.Map.ANNOTATION_GREEN
            });
            
            startPinLocation = {
                longitude       : evt.longitude,
                latitude        : evt.latitude
            }
            
            mapview.addAnnotation(startPin);
            ++completed;
            
            if (completed === 1) {
                Ti.Geolocation.forwardGeocoder(finishTextFieldContents, function(evt) {
                    var finishPin = Ti.Map.createAnnotation({
                        longitude   :   evt.longitude,
                        latitude    :   evt.latitude,
                        pincolor    :   Ti.Map.ANNOTATION_RED
                    });
            
                    finishPinLocation = {
                        longitude       : evt.longitude,
                        latitude        : evt.latitude
                    }
            
                    mapview.addAnnotation(finishPin);
                    
                    mapview.addRoute({
                        name : 'Route',
                        points : [startPinLocation, finishPinLocation],
                        color : 'green',
                        width : 1
                    });
                    
                });
            }
        });

You can do as Juhana suggested to nest the calls. The problem is that that is slow. You wait for a round-trip from the server and only then begin the next round trip, and only after 2 synchronous (ie non-parallel) round-trips do you perform the required task. It would be necessary if the data were dependent on each other, although it sounds like they aren't

As such, you can do as follows:

var completed = 0, values = [];

function handle(data){
   values.push(data);
   ++completed;
   if (completed === 2) {
      dataReadySoLetsDoStuff();
   }
}

fetchFromServer(params1, handle);
fetchFromServer(params2, handle);

function dataReadySoLetsDoStuff() {
   // both values are ready
}

Do you see how that will work asynchronously? There is a small problem that you can't distinguish between the values because their order isn't guaranteed, but you can easily change handle (currying, binding or wrapping for example) to fix that.

You can use other approaches, although they are all based on the same idea - count completed tasks until I guarantee all are done, and then perform the task we wanted to do...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM