Search code examples
javascriptnode.jsgoogle-mapscallbacksynchronous

Getting undefined for a variable even after defining it in a callback


I am using the following code for distance matric API for Google Maps, by using the google-distance-matrix API. The code is as follows:

app.get("/users", (req, res) => {
    // console.log(req.query);
    // res.send(req.query);
    const origins = [`${req.query.origin}`];
    const destinations = [`${req.query.dest}`];
    var dist;
    let carbonEstimate;
    try {
        // distance matrix calculation
        distance.matrix(origins, destinations, (err, distances) => {
            // console.log("Calculating distance...");
            if (err) {
                console.log(err);
                res.status(404).send("Error");
                return;
            }
            if (!distances) {
                res.send("No distance calculated");
                return;
            }
            dist = distances.rows[0].elements[0].distance.text.split(" ");
            console.log(dist);
        });
        console.log(dist);
        res.send("OK");
    }
    catch(err) {console.log(err); res.send("ERROR");}
});

The output on the console is as follows for the valid origin and destination 320 km apart:

undefined
["320", "km"]

Also, I do not want to send the distance, there are some other operations that will happen after the distance is calculated.

I understand that it is being created asynchronously, but I have no idea how to fix it. What should I do?


Solution

  • The reason for your problems is because of async execution and you not waiting for it. Here's what happens:

    // you define GET /users route, and whenever someone enters it, the callback is executed
    app.get("/users", (req, res) => {
        // console.log(req.query);
        // res.send(req.query);
        const origins = [`${req.query.origin}`];
        const destinations = [`${req.query.dest}`];
        var dist;
        let carbonEstimate;
        try {
            // distance matrix calculation
            // here you call ASYNC method (distance.matrix), which might take some time to execute
            // it's result would be handled with the callback
            // so js CONTINUES with the next line
            distance.matrix(origins, destinations, (err, distances) => {...});
            // here you print dist, but since the callback for distance.matrix
            // is NOT yet called (operation not done), the value is undefined
            console.log(dist);
            // you're sending the response BUT distance is not yet calculated
            res.send("OK"); // <-- MOVE this
        }
        catch(err) {console.log(err); res.send("ERROR");}
    });
    

    If you'd like to send back the distance, you must put res.send inside the callback of the distance.matrix:

    distance.matrix(origins, destinations, (err, distances) => {
      // console.log("Calculating distance...");
      if (err) {
        console.log(err);
        res.status(404).send("Error");
        return;
      }
      if (!distances) {
        res.send("No distance calculated");
        return;
      }
      dist = distances.rows[0].elements[0].distance.text.split(" ");
      console.log(dist);
      res.send("OK"); // -- you send the response AFTER distance calculated
    });