Looping through an array asynchronously changes values for different indexes - javascript

I have an asynchronous loop that sends the index value to save the results. However, for some reason, the first time this item loops, it records the value properly. The second time it loops. it changes the value in the first loop and the value in the second loop, and so forth and so on. It seems to do this inconsistently depending on the input.
Below is the code
promises[address_key] = addresses[address_key].nearest.map(function(currentValue, charger_key) { // This loops through items creating promises
return new Promise(function(resolve) {
addresses[address_key].nearest[charger_key].directions = get_driving_directions(addresses[address_key].nearest[charger_key]);
addresses[address_key].nearest[charger_key].map_img = get_static_map_url(addresses[address_key].nearest[charger_key]);
get_driving_distance(address_key, charger_key, resolve); // this calls the get_driving_distance function below
});
});
/* more code here */
// Calls distance matrix from Google's api.
function get_driving_distance(address_key, charger_key, resolve) {
var distance_matrix = new google.maps.DistanceMatrixService();
distance_matrix.getDistanceMatrix( // calls distance matrix in Google API
{
origins: [addresses[address_key].address],
destinations: [new google.maps.LatLng(addresses[address_key].nearest[charger_key].latitude, addresses[address_key].nearest[charger_key].longitude)],
unitSystem: google.maps.UnitSystem.IMPERIAL,
travelMode: 'DRIVING'
}, process_distance_matrix(address_key, charger_key, resolve) // calls process_distance_matrix function sending over variables necessary.
);
}
// processes data from the distance matrix in the function get_driving_distance
function process_distance_matrix(address_key, charger_key, callback) {
return function(response, status) {
if (response.rows[0].elements[0].status == 'OK') {
console.log("response", response, 'status', status, 'address_key', address_key, 'charger_key', charger_key);
console.log("Records before:", addresses[0].nearest[0].distance, response.rows[0].elements[0].distance.text, 'address_key', address_key, 'charger_key', charger_key);
// Update the global variable with the distance data. This is recording data in wrong fields.
addresses[address_key].nearest[charger_key].distance = {
'text': response.rows[0].elements[0].distance.text,
'number': response.rows[0].elements[0].distance.value / 1609.344,
'over_limit': (max_driving_distance ? (response.rows[0].elements[0].distance.value / 1609.344 > max_driving_distance) : false)
};
console.log("Records after:", addresses[0].nearest[0].distance, response.rows[0].elements[0].distance.text, 'address_key', address_key, 'charger_key', charger_key);
} else {
display_error(address_key + ') ' + addresses[address_key].address + ' - Error getting driving distance');
addresses[address_key].errors.push('Error getting driving distance');
progress_status.error++;
}
callback();
}
}
The rest of the code is too much to post, so here is a link to the rest of the code: https://jsfiddle.net/RobertoMejia/cqyyLh27/
The original loop is a for loop on line 68. This loops through addresses and passes address_key to refer to the global object.
There is a second loop on line 183. It is a .map loop. This runs through chargers, and passes charger_key to refer to the global object.
Notice the console.logs in the middle of the function. Those are to show how the variable changes where it shouldn't. The display the object in question before and after the declaration each time. It also shows the address key and the charger key at the time of execution.
Any help would be appreciated.

I think the problem is here in process_addresses:
addresses[address_key].nearest = charger_data.sort( sort_by_closest( addresses[address_key].geo ) );
// Takes the top results based on the number of results wanted.
addresses[address_key].nearest = addresses[address_key].nearest.slice(0, $('#number_of_results').val() );
If the same charger is near multiple addresses, that charger will be in the nearest array for all of them. So when you add the driving directions to the charger from one address, you're replacing the directions from the previous address.
There are two solutions:
The simplest is to clone the charger objects before putting them into the nearest array.
addresses[address_key].nearest = addresses[address_key].nearest.slice(0, $('#number_of_results').val()).map(function(charger) {
return $.extend({}, charger);
});
Another way is to use a different object to hold the directions, and make the charger a property of it:
addresses[address_key].nearest = addresses[address_key].nearest.slice(0, $('#number_of_results').val()).map(function(charger) {
return { charger: charger };
});
This is an application of Wheeler's famous aphorism: "All problems in computer science can be solved by another level of indirection"
Modified fiddle (using the first solution)

Related

Recursive Steam API Call does not terminate

I am calling an API endpoint for one of Steam's games through their web api using axios and promises in Node.js. Each JSON response from the endpoint returns 100 match objects, of which only about 10 to 40 (on average) are of interest to my use case. Moreover, I have observed that the data tends to be repeated if called many times within, say, a split second.
What I am trying to achieve is get 100 match_ids (not whole match objects) that fit my criteria in an array by continuously (recursively) calling the api until I get 100 unique match_ids that serve my purpose.
I am aware that calling the endpoint within a loop is naive and it exceeds the call limits of 1 request per second set by their web api. This is why I've resorted to recursion to ensure that each promise is resolved and the array filled with match_ids before proceeding on. The issue I am having is, my code does not terminate and at each stage of the recursive calls, the values are the same (e.g. last match id, the actual built up array, etc.)
function makeRequestV2(matchesArray, lastId) {
// base case
if (matchesArray.length >= BATCH_SIZE) {
console.log(matchesArray);
return;
}
steamapi
.getRawMatches(lastId)
.then(response => {
const matches = response.data.result.matches;
// get the last id of fetched chunk (before filter)
const lastIdFetched = matches[matches.length - 1].match_id;
console.log(`The last Id fetched: ${lastIdFetched}`);
let filteredMatches = matches
.filter(m => m.lobby_type === 7)
.map(x => x.match_id);
// removing potential dups
matchesArray = [...new Set([...matchesArray, ...filteredMatches])];
// recursive api call
makeRequestV2(matchesArray, lastIdFetched);
})
.catch(error => {
console.log(
"HTTP " + error.response.status + ": " + error.response.statusText
);
});
}
makeRequestV2(_matchIds);
// this function lies in a different file where the axios call happens
module.exports = {
getRawMatches: function(matchIdBefore) {
console.log("getRawMatches() executing.");
let getURL = `${url}${config.ENDPOINTS.GetMatchHistory}/v1`;
let parameters = {
params: {
key: `${config.API_KEY}`,
min_players: `${initialConfig.min_players}`,
skill: `${initialConfig.skill}`
}
};
if (matchIdBefore) {
parameters.start_at_match_id = `${matchIdBefore}`;
}
console.log(`GET: ${getURL}`);
return axios.get(getURL, parameters);
}
}
I'm not exceeding the request limits and all that, but the same results keep coming up.
BATCH_SIZE is 100 and
_matchIds = []
I would start with replacing the line:
matchesArray = [...new Set([...matchesArray, ...filteredMatches])];
with this one:
filteredMatches.filter(item => matchesArray.indexOf(item) === -1).forEach(item=>{
matchesArray.push(item)
})
What you were doing was that you effectively replaced the matchesArray var inside your function with new reference. I mean the var that you sent in function parameter from outside was no longer the same var inside the function. If you use matchesArray.push - you do not change the var reference though and the var in outer scope is accurately updated - just as is your intention.
This is the reason why _matchIds remains empty: each time there is a call to makeRequestV2, the inner variable matchesArray becomes 'detouched' from outer scope (during assignment statement execution) and although it gets populated, the outer scoped var still points to the original reference and stays untouched.

How to delay a function like this? [duplicate]

Using the Google Geocoder v3, if I try to geocode 20 addresses, I get an OVER_QUERY_LIMIT unless I time them to be ~1 second apart, but then it takes 20 seconds before my markers are all placed.
Is there any other way to do it, other than storing the coordinates in advance?
No, there is not really any other way : if you have many locations and want to display them on a map, the best solution is to :
fetch the latitude+longitude, using the geocoder, when a location is created
store those in your database, alongside the address
and use those stored latitude+longitude when you want to display the map.
This is, of course, considering that you have a lot less creation/modification of locations than you have consultations of locations.
Yes, it means you'll have to do a bit more work when saving the locations -- but it also means :
You'll be able to search by geographical coordinates
i.e. "I want a list of points that are near where I'm now"
Displaying the map will be a lot faster
Even with more than 20 locations on it
Oh, and, also (last but not least) : this will work ;-)
You will less likely hit the limit of X geocoder calls in N seconds.
And you will less likely hit the limit of Y geocoder calls per day.
You actually do not have to wait a full second for each request. I found that if I wait 200 miliseconds between each request I am able to avoid the OVER_QUERY_LIMIT response and the user experience is passable. With this solution you can load 20 items in 4 seconds.
$(items).each(function(i, item){
setTimeout(function(){
geoLocate("my address", function(myLatlng){
...
});
}, 200 * i);
}
Unfortunately this is a restriction of the Google maps service.
I am currently working on an application using the geocoding feature, and I'm saving each unique address on a per-user basis. I generate the address information (city, street, state, etc) based on the information returned by Google maps, and then save the lat/long information in the database as well. This prevents you from having to re-code things, and gives you nicely formatted addresses.
Another reason you want to do this is because there is a daily limit on the number of addresses that can be geocoded from a particular IP address. You don't want your application to fail for a person for that reason.
I'm facing the same problem trying to geocode 140 addresses.
My workaround was adding usleep(100000) for each loop of next geocoding request. If status of the request is OVER_QUERY_LIMIT, the usleep is increased by 50000 and request is repeated, and so on.
And of cause all received data (lat/long) are stored in XML file not to run request every time the page is loading.
EDIT:
Forgot to say that this solution is in pure js, the only thing you need is a browser that supports promises https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
For those who still needs to accomplish such, I've written my own solution that combines promises with timeouts.
Code:
/*
class: Geolocalizer
- Handles location triangulation and calculations.
-- Returns various prototypes to fetch position from strings or coords or dragons or whatever.
*/
var Geolocalizer = function () {
this.queue = []; // queue handler..
this.resolved = [];
this.geolocalizer = new google.maps.Geocoder();
};
Geolocalizer.prototype = {
/*
#fn: Localize
#scope: resolve single or multiple queued requests.
#params: <array> needles
#returns: <deferred> object
*/
Localize: function ( needles ) {
var that = this;
// Enqueue the needles.
for ( var i = 0; i < needles.length; i++ ) {
this.queue.push(needles[i]);
}
// return a promise and resolve it after every element have been fetched (either with success or failure), then reset the queue.
return new Promise (
function (resolve, reject) {
that.resolveQueueElements().then(function(resolved){
resolve(resolved);
that.queue = [];
that.resolved = [];
});
}
);
},
/*
#fn: resolveQueueElements
#scope: resolve queue elements.
#returns: <deferred> object (promise)
*/
resolveQueueElements: function (callback) {
var that = this;
return new Promise(
function(resolve, reject) {
// Loop the queue and resolve each element.
// Prevent QUERY_LIMIT by delaying actions by one second.
(function loopWithDelay(such, queue, i){
console.log("Attempting the resolution of " +queue[i-1]);
setTimeout(function(){
such.find(queue[i-1], function(res){
such.resolved.push(res);
});
if (--i) {
loopWithDelay(such,queue,i);
}
}, 1000);
})(that, that.queue, that.queue.length);
// Check every second if the queue has been cleared.
var it = setInterval(function(){
if (that.queue.length == that.resolved.length) {
resolve(that.resolved);
clearInterval(it);
}
}, 1000);
}
);
},
/*
#fn: find
#scope: resolve an address from string
#params: <string> s, <fn> Callback
*/
find: function (s, callback) {
this.geolocalizer.geocode({
"address": s
}, function(res, status){
if (status == google.maps.GeocoderStatus.OK) {
var r = {
originalString: s,
lat: res[0].geometry.location.lat(),
lng: res[0].geometry.location.lng()
};
callback(r);
}
else {
callback(undefined);
console.log(status);
console.log("could not locate " + s);
}
});
}
};
Please note that it's just a part of a bigger library I wrote to handle google maps stuff, hence comments may be confusing.
Usage is quite simple, the approach, however, is slightly different: instead of looping and resolving one address at a time, you will need to pass an array of addresses to the class and it will handle the search by itself, returning a promise which, when resolved, returns an array containing all the resolved (and unresolved) address.
Example:
var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){
console.log(res);
});
Console output:
Attempting the resolution of Georgia
Attempting the resolution of China
Attempting the resolution of Dragons are thugs...
Attempting the resolution of California
ZERO_RESULTS
could not locate Dragons are thugs...
Attempting the resolution of Italy
Object returned:
The whole magic happens here:
(function loopWithDelay(such, queue, i){
console.log("Attempting the resolution of " +queue[i-1]);
setTimeout(function(){
such.find(queue[i-1], function(res){
such.resolved.push(res);
});
if (--i) {
loopWithDelay(such,queue,i);
}
}, 750);
})(that, that.queue, that.queue.length);
Basically, it loops every item with a delay of 750 milliseconds between each of them, hence every 750 milliseconds an address is controlled.
I've made some further testings and I've found out that even at 700 milliseconds I was sometimes getting the QUERY_LIMIT error, while with 750 I haven't had any issue at all.
In any case, feel free to edit the 750 above if you feel you are safe by handling a lower delay.
Hope this helps someone in the near future ;)
I have just tested Google Geocoder and got the same problem as you have.
I noticed I only get the OVER_QUERY_LIMIT status once every 12 requests
So I wait for 1 second (that's the minimum delay to wait)
It slows down the application but less than waiting 1 second every request
info = getInfos(getLatLng(code)); //In here I call Google API
record(code, info);
generated++;
if(generated%interval == 0) {
holdOn(delay); // Every x requests, I sleep for 1 second
}
With the basic holdOn method :
private void holdOn(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
// ignore
}
}
Hope it helps
This worked well for me, after intermittent trial and error over the past couple days. I am using react instant-search-hooks via Algolia with Nextjs and Sanity for a new jobs site for a large company.
Postal Code is a facet for filtering/sorting/query matching that is defined in the algolia index. In another script file, I map out all of these facets (postal code, city, etc); Now that I have 100 returned files they can be mapped out by iterating through a mapped asynchronous import and the lat/lng coords matched to the corresponding zip codes defining a job posting (there are ~2500 postings but only ~100 zip codes to narrow down the coordinates of)
import * as dotenv from "dotenv";
dotenv.config();
import {
googleNetwork,
axiosConfig as googleAxiosConfig
} from "../utils/google-axios";
import JSONData from "../../public/data/postalCode/2022/05/26.json";
import fs from "fs";
import { join } from "path";
import type { GeneratedGeolocData } from "../types/algolia";
import { timezoneHelper } from "../utils/timezone-helper";
import { Unenumerate } from "../types/helpers";
let i = 0;
i < JSONData.postalCodes.facetHits.length;
i++;
const getGeoCode = (
record: Unenumerate<typeof JSONData.postalCodes.facetHits>
) =>
function () {
return JSONData.postalCodes.facetHits.map(async (data = record, u) => {
const googleBase = process.env.NEXT_PUBLIC_GOOGLE_MAPS_BASE_PATH ?? "";
const googleApiKey =
process.env.NEXT_PUBLIC_TAKEDA_JOBS_GOOGLE_SERVICES ?? "";
const params: (string | undefined)[][] = [
["address", data.value],
["key", googleApiKey]
];
const query = params
.reduce<string[]>((arr, [k, v]) => {
if (v) arr.push(`${k}=${encodeURIComponent(v)}`);
return arr;
}, [])
.join("&");
return await googleNetwork("GET")
.get(`${googleBase}geocode/json?${query}`, googleAxiosConfig)
.then(dat => {
const geoloc = dat.data as GeneratedGeolocData;
const {
[0]: Year,
[2]: Month,
[4]: Day
} = new Date(Date.now())
.toISOString()
.split(/(T)/)[0]
.split(/([-])/g);
const localizedTimestamp = timezoneHelper({
dateField: new Date(Date.now()),
timezone: "America/Chicago"
});
return setTimeout(
() =>
fs.appendFileSync(
join(
process.cwd(),
`public/data/geoloc/${Year}/${Month}/${Day}-${[i]}.json`
),
JSON.stringify(
{
generated: localizedTimestamp,
_geoloc: {
postalCode: data.value,
geolocation: geoloc
}
},
null,
2
)
),
1000
);
});
});
};
getGeoCode(JSONData.postalCodes.facetHits[i]);
It took a lot less time than anticipated -- under 4 seconds for 100 unique results to generate
Context on the Unenumerate type -- Unenumerate strips the internal repeating unit within an array:
type Unenumerate<T> = T extends Array<infer U> ? U : T;

Ionic Angular JS distance shows twice then disappears (NaN)

I have been battling with this pretty much for the whole day.
In list1.ts:
inside the constructor I have the following code, which gets an array of items, and places them in this.items - after that it gets the users' current position and injects a distance variable (calculated from lat/lng from firebase and lat/lng from user) into this.items
this.categoryId = this.navParams.get('categoryId');
afoDatabase.list('/list', {query: {
orderByChild: "categoryId",
equalTo: parseInt(this.categoryId)
}}).subscribe(listItems => {
this.items = listItems;
this.geolocation.getCurrentPosition({timeout:15000}).then((resp) => {
this.myLat = resp.coords.latitude;
this.myLong = resp.coords.longitude;
}).catch((error) => {
console.log('Error getting location', error);
});
for (var i = 0, len = this.items.length; i < len; i++) {
this.distance = this.calculateDistance(this.myLat, this.myLong, this.items[i].lat, this.items[i].lng);
this.items[i]["distance"] = Math.round(this.distance);
console.log('testing myLat', this.myLat)
console.log('testing myLong', this.myLong)
}
console.log('testing inject', this.items)
loadingPopup.dismiss().catch(() => {});
});
In list1.html:
I show the distance using the following:
{{item.distance}}
This works fine, and the distance shows. However, if I go back a page (to the root page), and then go back to the page where I calculate the distance, I get the distance fine as well ... However, the 3rd time it just throws NaN
lat/lng shows values in console, and distance:4625 for first try
lat/lng shows values in console, and distance:4625 for second try
lat/lng shows undefined in console, and distance:NaN for the third try
If you have any idea, please let me know :)
Thanks.
I believe there are 2 problems here:
this.geolocation.getCurrentPosition({timeout:15000}).then((resp) => {
this.myLat = resp.coords.latitude;
this.myLong = resp.coords.longitude;
First this code is asynchronous, so it will be executed after your for loop, and so this.myLat and this.myLong will have the previously assigned values, that I believe will be from some initialisation or something else in your code.
Second, if you put a console.log(this.myLat, this.myLong) right after the last line of the code I have posted, I believe you will see that they are undefined. So, maybe coords doesn't have latitude / longitude properties? Try to console.log(resp.coords) to check.

Assemble paginated ajax data in a Bacon FRP stream

I'm learning FRP using Bacon.js, and would like to assemble data from a paginated API in a stream.
The module that uses the data has a consumption API like this:
// UI module, displays unicorns as they arrive
beautifulUnicorns.property.onValue(function(allUnicorns){
console.log("Got "+ allUnicorns.length +" Unicorns");
// ... some real display work
});
The module that assembles the data requests sequential pages from an API and pushes onto the stream every time it gets a new data set:
// beautifulUnicorns module
var curPage = 1
var stream = new Bacon.Bus()
var property = stream.toProperty()
var property.onValue(function(){}) # You have to add an empty subscriber, otherwise future onValues will not receive the initial value. https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-property-updated
var allUnicorns = [] // !!! stateful list of all unicorns ever received. Is this idiomatic for FRP?
var getNextPage = function(){
/* get data for subsequent pages.
Skipping for clarity */
}
var gotNextPage = function (resp) {
Array.prototype.push.apply(allUnicorns, resp) // just adds the responses to the existing array reference
stream.push(allUnicorns)
curPage++
if (curPage <= pageLimit) { getNextPage() }
}
How do I subscribe to the stream in a way that provides me a full list of all unicorns ever received? Is this flatMap or similar? I don't think I need a new stream out of it, but I don't know. I'm sorry, I'm new to the FRP way of thinking. To be clear, assembling the array works, it just feels like I'm not doing the idiomatic thing.
I'm not using jQuery or another ajax library for this, so that's why I'm not using Bacon.fromPromise
You also may wonder why my consuming module wants the whole set instead of just the incremental update. If it were just appending rows that could be ok, but in my case it's an infinite scroll and it should draw data if both: 1. data is available and 2. area is on screen.
This can be done with the .scan() method. And also you will need a stream that emits items of one page, you can create it with .repeat().
Here is a draft code (sorry not tested):
var itemsPerPage = Bacon.repeat(function(index) {
var pageNumber = index + 1;
if (pageNumber < PAGE_LIMIT) {
return Bacon.fromCallback(function(callback) {
// your method that talks to the server
getDataForAPage(pageNumber, callback);
});
} else {
return false;
}
});
var allItems = itemsPerPage.scan([], function(allItems, itemsFromAPage) {
return allItems.concat(itemsFromAPage);
});
// Here you go
allItems.onValue(function(allUnicorns){
console.log("Got "+ allUnicorns.length +" Unicorns");
// ... some real display work
});
As you noticed, you also won't need .onValue(function(){}) hack, and curPage external state.
Here is a solution using flatMap and fold. When dealing with network you have to remember that the data can come back in a different order than you sent the requests - that's why the combination of fold and map.
var pages = Bacon.fromArray([1,2,3,4,5])
var requests = pages.flatMap(function(page) {
return doAjax(page)
.map(function(value) {
return {
page: page,
value: value
}
})
}).log("Data received")
var allData = requests.fold([], function(arr, data) {
return arr.concat([data])
}).map(function(arr) {
// I would normally write this as a oneliner
var sorted = _.sortBy(arr, "page")
var onlyValues = _.pluck(sorted, "value")
var inOneArray = _.flatten(onlyValues)
return inOneArray
})
allData.log("All data")
function doAjax(page) {
// This would actually be Bacon.fromPromise($.ajax...)
// Math random to simulate the fact that requests can return out
// of order
return Bacon.later(Math.random() * 3000, [
"Page"+page+"Item1",
"Page"+page+"Item2"])
}
http://jsbin.com/damevu/4/edit

Javascript closures with google geocoder

i still have some problems with javascript closures, and input/output variables.
Im playing with google maps api for a no profit project: users will place the marker into a gmap, and I have to save the locality (with coordinates) in my db.
The problem comes when i need to do a second geocode in order to get a unique pairs of lat and lng for a location: lets say two users place the marker in the same town but in different places, I dont want to have the same locality twice in the database with differents coords.
I know i can do the second geocode after the user select the locality, but i want to understand what am i mistaking here:
// First geocoding, take the marker coords to get locality.
geocoder.geocode(
{
'latLng': new google.maps.LatLng($("#lat").val(), $("#lng").val()),
'language': 'it'
},
function(results_1, status_1){
// initialize the html var inside this closure
var html = '';
if(status_1 == google.maps.GeocoderStatus.OK)
{
// do stuff here
for(i = 0, geolen = results_1[0].address_components.length; i != geolen)
{
// Second type of geocoding: for each location from the first geocoding,
// i want to have a unique [lat,lan]
geocoder.geocode(
{
'address': results_1[0].address_components[i].long_name
},
function(results_2, status_2){
// Here come the problem. I need to have the long_name here, and
// 'html' var should increment.
coords = results_2[0].geometry.location.toUrlValue();
html += 'some html to let the user choose the locality';
}
);
}
// Finally, insert the 'html' variable value into my dom...
//but it never gets updated!
}
else
{
alert("Error from google geocoder:" + status_1)
}
}
);
I tryed with:
// Second type of geocoding: for each location from the first geocoding, i want
// to have a unique [lat,lan]
geocoder.geocode(
{
'address': results_1[0].address_components[i].long_name
},
(function(results_2, status_2, long_name){
// But in this way i'll never get results_2 or status_2, well, results_2
// get long_name value, status_2 and long_name is undefined.
// However, html var is correctly updated.
coords = results_2[0].geometry.location.toUrlValue();
html += 'some html to let the user choose the locality';
})(results_1[0].address_components[i].long_name)
);
And with:
// Second type of geocoding: for each location from the first geocoding, i want to have
// a unique [lat,lan]
geocoder.geocode(
{
'address': results_1[0].address_components[i].long_name
},
(function(results_2, status_2, long_name){
// But i get an obvious "results_2 is not defined" error (same for status_2).
coords = results_2[0].geometry.location.toUrlValue();
html += 'some html to let the user choose the locality, that can be more than one';
})(results_2, status_2, results_1[0].address_components[i].long_name)
);
Any suggestion?
EDIT:
My problem is how to pass an additional arguments to the geocoder inner function:
function(results_2, status_2, long_name){
//[...]
}
becose if i do that with a clousure, I mess with the original parameters (results_2 and status_2)
If I'm understanding you correctly:
Your problem in the first example is that the second (innermost) geocode's callback function (which appends the string to html) will not have executed by the time you reach the line with the comment Finally, insert the 'html' variable value into my dom....
You are effectively launching the second geocode request, and then inserting html before the operation has completed.
Regarding passing an extra argument to the callback, you could always make a function that creates and returns a function:
eg.
function(my_argument)
{
return(function(cb1,cb2) { ... });
}(my_argument_value);
Then you can pass in whatever you want for my_argument_value, and the innermost code (...) will see it as well as the two callback args.
The return value of this function is what you pass as the callback to the geocode call.

Categories

Resources