Async, Callbacks, Closure, Oh My

Here is what I am trying to do and fail:

I have MongoDB filled with GPS readings from a device attached to the car. The readings are timestamped and have a lat / lng value.

For each reading, I want to create a Position class that contains location, timestamp, and other information.

To build this on Google Maps, I want to create a Route class, which consists of an array of Positions objects.

The main function at the top loads the route from the sample JSON file (to avoid CSRF problems ... of a different story), creates Position objects and route objects in order. Problems arise when I try to build a route.

var positions = this.getPositions(); 

If i type

 console.log(positions); 

right below this line, it prints an array of positions. It takes a little to do this because it is big, but it works.

If, however, I type

 console.log(positions[0]); 

it will not work because line items have not yet been loaded.

What should I do?

I am using classy.js from http://classy.pocoo.org , but I have verified that this is not a problem.

 function main() { var route = Route('20120928_025650_0'); route.plot(); } var Route = Class.$extend({ __init__ : function(imaging_run_id) { this.imaging_run_id = imaging_run_id; this.positions = []; this.load(); }, getPositions : function() { return (this.positions); }, load : function() { //var url='http://localhost:5001/gps/by_imaging_run_id/' + this.imaging_run_id; var test_url = '/static/20120928_025650_0.json'; var me = this; $.getJSON(test_url, function(route) { for(var position in route) { var obj = route[position]; var new_position = Position(obj['_id'], obj['lat'], obj['lng'], obj['timestamp'], obj['epoch_timestamp'], obj['is_valid']); me.pushPositions(new_position); } me.orderPositions(); }) .error(function(jqXhr, textStatus, error) { alert("ERROR: " + textStatus + ", " + error); }); }, orderPositions : function() { var unsorted_array = this.getPositions(); var sorted = unsorted_array.sort(function(a,b){ //Custom sort function return a['timestamp'] - b['timestamp']; //Sort ascending }); this.setPositions(sorted); }, plot : function() { var positions = this.getPositions(); var points = []; var bounds = new google.maps.LatLngBounds(); for(var i=0; i<positions.length; i++) { var obj = positions[i]; var point = new google.maps.LatLng(obj['location'][0], obj['location'][1]); points.push(point); bounds.extend(point); } // Create the polyline. var route = new google.maps.Polyline({ path: points, strokeColor: '#e81971', strokeOpacity: 1.0, strokeWeight: 4 }); map.fitBounds(bounds); route.setMap(map); } }); var Position = Class.$extend({ __init__ : function(id, lat, lng, timestamp, epoch_timestamp, valid) { this.id = id; this.location = [lat, lng]; this.timestamp = new Date(timestamp); this.epoch_timestamp = new Date(epoch_timestamp); this.valid = valid; this.anchor_location; },..... 
+4
source share
1 answer

If I understood correctly, you need to do something like this:

 var positions = this.getPositions(function(positions) { console.log(positions[0]); }); 

That is, you want to write "getPositions" in such a way that it takes one callback parameter, which is called after successful positioning of positions and an array of positions is passed. In getPositions you can check if the positions have already been loaded, and if so, call the callback immediately. Otherwise, you add them to the callback queue (for example, this.positionsLoadedCallbacks ) through which you iterate after loading all the positions (I think it will be somewhere in your load function near me.orderPositions() ).

For example, your getPositions function might look like this:

 getPositions : function(callback) { if(this.positions !== null) { callback(this.positions); return; } this.positionsLoadedCallbacks.push(callback); }, 

Somewhere after you are sure that the positions are loaded (i.e. in the loadJSON callback), you need to add something like this:

 for(var i=0; i < this.positionsLoadedCallbacks.length; i++) { this.positionsLoadedCallbacks[i](this.positions); } 

And don't forget to initialize this.positionsLoadedCallbacks :)

console.log trivia

The reason console.log(positions) works, and console.log(positions[0]) not easy: if you pass an object reference to console.log , the object will be checked when you click the small expand arrow and try to take look inside the object / array. By the time you click this arrow, the positions are loaded, of course. However, if you pass a specific element of the array (for example, positions[0] ), it will try to find this value up, find that it is still undefined , and write the result to the console.

Try it yourself:

 var i = []; console.log([i]); i.push(123); 

The previous snippet, in chrome 24, shows [Array[0]] in the console, but when I expand it, it tells me that the array is like length: 1 and that its first element is 123

+3
source

Source: https://habr.com/ru/post/1441401/


All Articles