mathiflip
mathiflip

Reputation: 67

arrays in array formatting in javascript

I'm trying to fix this bug in my code and I can't find a solution anywhere so it is driving me crazy. I'm giving up trying it myself and gonna ask everybody here for advice.

I'm making a simple ISS tracker in javascript as a beginners exercise. Fetching the position from an API and plotting it on a map with leaflet.js

Now i'm stuck with drawing a polyline, because I can't return an array of latlngs in a correct format and I don't get why.

So I have an async getISS() function that draws the current position on the map (which works fine) and returns the current timestamp. then I have another async function getISS_at_time() returning the lat,lng position for a specified timestamp. but there is the problem. I need to put all the [lat, lng] positions in to an array to feed it to the L.polyline function but I don't understand how.

async function getISS_at_time(timestamp) {
    const api_url =
      "https://api.wheretheiss.at/v1/satellites/25544/positions?timestamps=" +
      timestamp;

    const res = await fetch(api_url);
    const data = await res.json();
    const lat = data[0].latitude;
    const lng = data[0].longitude;
    const json_data = '{"lat":' + lat + ', "lng": ' + lng + "}";

    return JSON.parse(json_data);
  }

  async function getISS() {
    const result = await fetch(api_url);
    const data = await result.json();
    const position = [data.latitude, data.longitude];

    marker.setLatLng(position);
    iss_map.setView(position, 2);

    return data.timestamp;
  }

  getISS().then((timestamp) => {
    let start = timestamp - 45 * 60;

    for (let i = 0; i < 3; ++i) {
      timestamp = start + 60 * i;

      var positions = [];
      getISS_at_time(timestamp).then((pos) => {
        //here i'm getting the lat, lng position and trying to put it in a new array
        positions[i] = [pos.lat, pos.lng];
      });
    }
    // this is a test var with a correct array format to feed to the polyline function
    var latlngs = [
      [38.91, -77.07],
      [37.77, -79.43],
      [39.04, -85.2],
    ];
    console.log(Array.isArray(positions[0]));  // returns false
    console.log(positions); // looks exactly the same as console.log(latlngs) in the Chrome console (see img)
    console.log(Array.isArray(latlngs[0])); // returns true
    console.log(latlngs);

    // works fine
    var poly = L.polyline(latlngs, { color: "red" }).addTo(iss_map);
    // draws nothing!
    var poly = L.polyline(positions, { color: "red" }).addTo(iss_map);
  });

enter image description here

I also tried with positions.push(pos) instead of positions[i] = pos but without success

Upvotes: 1

Views: 204

Answers (1)

trincot
trincot

Reputation: 350147

Your code is accessing positions without awaiting that the promises (returned by getISS_at_time) are resolved.

Here is how you can fix that:

getISS().then((timestamp) => {
    let start = timestamp - 45 * 60;

    return Promise.all(Array.from({length: 3}, (_, i) => {
        return getISS_at_time(start + 60 * i).then((pos) => [pos.lat, pos.lng]);
    }));
}).then(positions => {
    console.log(Array.isArray(positions[0]));
    console.log(positions);
    var poly = L.polyline(positions, { color: "red" }).addTo(iss_map);
    // ... more code working on this data
});

As you already use async await syntax, you can also use an immediately invoked async function to do the same:

(async function () {
    let timestamp = await getISS();
    let start = timestamp - 45 * 60;
    let positions = await Promise.all(Array.from({length: 3}, async (_, i) => {
        let pos = await getISS_at_time(start + 60 * i);
        return [pos.lat, pos.lng];
    }));
    console.log(Array.isArray(positions[0]));
    console.log(positions);
    var poly = L.polyline(positions, { color: "red" }).addTo(iss_map);
    // ... more code working on this data
})(); // immediately invoked

Other remark

It is really bad practice to construct JSON format with string concatenation:

const json_data = '{"lat":' + lat + ', "lng": ' + lng + "}";
return JSON.parse(json_data);

Instead, just construct the object -- and you can even use short-cut object literal syntax for that:

return { lat, lng };

Upvotes: 3

Related Questions