Search code examples
javascriptnode.jsasynchronouspromiseknex.js

Why is my function returning a Promise { <pending> } instead of my entries?


Problem:

I want to return companies of a certain range (km) from a certain location. These companies are in a database that currently contains 2 entries for testing. Among other things, I also use the distance matrix API from Google to calculate the distance.

After it didn't work a debug showed me that the function returns[Promise {<pending>}, Promise {<pending>}].

Code:

const
    axios = require("axios"),
    knex = require('knex')(require('../knexfile'));

const getAllByDistance = (location) =>
    knex('companies')
        .select()
        .then(entries =>
            entries.map(company =>
                getDistance(location, `${company.street}, ${company.postcode} ${company.place}`)
                    .then(distance => {
                        knex('companies')
                            .select()
                            .where(parseInt(company.maximum_distance_km) >= parseInt(distance.toString().slice(0, -3)))
                    }))
        );

const getDistance = async (loc1, loc2) => {
    const origins = encodeURI(`?origins=${loc1}`);
    const destinations = encodeURI(`&destinations=${loc2}`);
    const key = `&key=${process.env.VUE_APP_GOOGLE_MAPS_API_KEY}`;
    const config = {
        method: 'get',
        url: `https://maps.googleapis.com/maps/api/distancematrix/json${origins}${destinations}${key}`,
        headers: {}
    };
    return await axios(config)
        .then((response) => {
            return response.data['rows'][0]['elements'][0]['distance'].value;
        })
        .catch((err) => {
            console.log(err);
        });
}

The function call with debug:

companyService
        .getByDistance(location)
        .then(companies => {
            console.log(companies)
            res.status(200);
            res.json(companies);
        })
        .catch(err => {
            res.status(500);
            res.end(`Error: ${err.message}`);
        });

Solution

  • I would suggest you start by going full-on async/await instead of a mixture of that and then().

    Starting at the getDistance method:

    const getDistance = async (loc1, loc2) => {
        const origins = encodeURI(`?origins=${loc1}`);
        const destinations = encodeURI(`&destinations=${loc2}`);
        const key = `&key=${process.env.VUE_APP_GOOGLE_MAPS_API_KEY}`;
        const config = {
            method: 'get',
            url: `https://maps.googleapis.com/maps/api/distancematrix/json${origins}${destinations}${key}`,
            headers: {}
        };
        try{
            const response = await axios(config)
            return response.data['rows'][0]['elements'][0]
        }
        catch(e){
            console.log(e);
            // return 0; // What should we return if there's an error?
        }            
    }
    

    Now the getAllDistances method becomes much easier to manage without all that nesting (caveat: I know nothing about knex, I'm only going by your code which as I commented seems odd that you repeatedly query all your companies.... but trying to replicate the same functionality that I think you have)

    const getAllByDistance = async (location) => {
       const entries = await knex("companies").select();
    
       const results = [];
       for(let i=0;i<entries.length;i++){
           const company = entries[i];
           const distance = await getDistance(location, `${company.street}, ${company.postcode} ${company.place}`);
    
           const result = await knex('companies')
                                .select()
                                .where(parseInt(company.maximum_distance_km) >= parseInt(distance.toString().slice(0, -3)));
            results.push(result);
       }
       return results;
    }
    

    The above has some drawbacks, mainly that it goes sequentially through the original list of companies getting the distance, and then loading up all the companies within that distance - but it will get you started to a more efficient algorithm i'm sure.