2

I've written a piece of code to gather the coordinates of some US cities from an API.

Basically:

  • I have a big array (data) with some info on companies, organised by the US state they're located in
  • I create an empty array called coords
  • I iterate through my big array where all the data is to find the unique cities in each state
  • for each city, I fetch the coordinates from an API and push that in my array coords
  • After the loop, I console.log the coords array, and it works.

Shouldn't the console.log(coords) just display an empty array?

When I try to do anything else (e.g. JSON.stringify), I get an empty array (probably beacause the after-loop code is executing before the promises resolve? But then why not console.log?)

Can someone explain this weird behavior to me?

// const data = ...allmydata...
let coords = []
const key = 'MYKEY'

for(let state in data){
  coords[state] = []
  // get the list of unique cities
  let cities = [...new Set( data[state].map( x => x['Largest Location'] ) )]

  // this is the fetching loop: for each city name
  // I'm getting the coordinates asynchronously
  cities.forEach( (city) => {
    coords[state][city] = {
      lat: undefined,
      lng: undefined
    }
    let req = `http://open.mapquestapi.com/geocoding/v1/address?key=${key}&location=${city},${state}`
    fetch(req)
    .then( res => res.json() )
    .then( res => {
      coords[state][city]['lat'] = res.results[0].locations[0].latLng.lat
      coords[state][city]['lng'] = res.results[0].locations[0].latLng.lng
    })
    .catch( err => console.log(err) )
  })

}
// out of the loop

// this displays my array nicely structured in the console
console.log(coords)

// this displays []
console.log(coords.map(x => x))

// this displays []
console.log(JSON.stringify(coords))

I don't think it's a duplicate from all the questions about why values are undefined in async code (which I've read a fair share), this time the value looks defined where it shouldn't IMHO.

Thanks in advance

henrilf
  • 33
  • 4
  • `console.log()` is passed a reference to an object (or array), so the value in the Console changes as the object changes.. – Rounin Oct 04 '19 at 15:05
  • 1
    @Rounin ok, so if I understand correctly, if I pass an object to the log function, it is a reference, but if I pass something else e.g. JSON.stringify(myObject), then js tries to interpret what's between parentheses and pass a reference to the new result to the console? – henrilf Oct 04 '19 at 15:19
  • Pretty much, as I understand it, yes. If you log a raw object, then the log will display an updatable reference to that object. If you log the result of a computation then it will log only the synchronous result of that computation. @Evert's answer below is a good summary. – Rounin Oct 04 '19 at 15:22
  • 1
    Great, thanks, it seems it was already in the reference: https://developer.mozilla.org/en-US/docs/Web/API/Console/log – henrilf Oct 04 '19 at 15:26

1 Answers1

1

I've had a look at this in Firefox, just to make sure I got this right.

What I believe is happening, is that you are logging your array, but at the time it is still empty.

However, with nicer consoles from today, in firefox at least I'm not just given the variable, but a reference to the variable.

After the results come in, that existing variable gets added to. When I click the little 'expand' triangle, I actually notice that I can see data in my empty array that I've added after logging.

Evert
  • 93,428
  • 18
  • 118
  • 189
  • Thanks, I can't believe I did not check the console.log reference before asking: https://developer.mozilla.org/en-US/docs/Web/API/Console/log – henrilf Oct 04 '19 at 15:26