IsaIkari
IsaIkari

Reputation: 1154

How to wait until request.get finish then conduct the next block in node.js

I am new to NodeJS and I am working on a request.get problem. My goal is simply have a function that request the web, and when request finished, the function returns the result, otherwise it returns an error message.

Here's the function that I used for request:

var artistNameIdMap = {};
var getPopularArtists = async () => {
    //https://nodejs.org/api/http.html#http_http_request_options_callback
    var options = {
        url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
        headers: { 'Authorization': 'Bearer ' + access_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'},
        json: true
    }
    
    request.get(options, function(error, response, body) {
        if (response.statusCode === 200){
            console.log("inside");
            artistNameIdMap = getArtistNameIdMap(body, artistNameIdMap);
        } else {
            res.send("get popular error");
            return {};
        }
    })

    console.log("outside");
    return artistNameIdMap;


module.exports = {
    GetPopularArtists: getPopularArtists
}

And this function is included in a getPopular.js file. I would like to call the function in another file playlist.js.

In playlist.js, I wrote

const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", (req, res) =>{
    const artistNameIdMap = getPopular.GetPopularArtists();
    console.log(artistNameIdMap);
    let BPM = req.params.BPM;
    res.send(BPM);
})

However the result I got is

outside
Promise { {} }
inside

It seems like the return was before the request gives back the information. I wonder what should I write to make sure that I can obtain the correct artistNameIdMap at playlist.js.

Upvotes: 0

Views: 1620

Answers (2)

jfriend00
jfriend00

Reputation: 707298

Though you've already accepted an answer, there are a couple of additional things I can add. First, the request() library has been deprecated and it is not recommended for new code. Second, there is a list of recommended alternatives here. Third, all these alternatives support promises natively as that is the preferred way to program asynchronous code in modern nodejs programming.

My favorite alternative is got() because I find it's interface simple and clean to use and it has the features I need. Here's how much simpler your code would be using got():

const got = require('got');
let artistNameIdMap = {};

async function getPopularArtists() {
    const options = {
        headers: { 'Authorization': 'Bearer ' + access_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'},
    };
    const url = CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath;
    let results = await got(url, options).json();
    // update local cache object
    artistNameIdMap = getArtistNameIdMap(results, artistNameIdMap);
    return artistNameIdMap;
}

module.exports = {
    GetPopularArtists: getPopularArtists
}

Note: The caller should supply error handling based on the returned promise.

GetPopularArtists().then(results => {
    console.log(results);
}).catch(err => {
    console.log(err);
});

Upvotes: 1

Bravo
Bravo

Reputation: 6264

Since you want to use Promises, use it like this

const getPopularArtists = () => new Promise((resolve, reject) {
    const options = {
        url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        json: true
    }

    request.get(options, (error, response, body) => {
        if (error) {
            reject(error);
        } else if (response.statusCode === 200) {
            console.log("inside");
            resolve(getArtistNameIdMap(body, artistNameIdMap));
        } else {
            reject("get popular error");
        }
    });
});

module.exports = {
    GetPopularArtists: getPopularArtists
}

And use it like

const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", async (req, res) =>{
    try {
        const artistNameIdMap = await getPopular.GetPopularArtists();
        console.log(artistNameIdMap);
        let BPM = req.params.BPM;
        res.send(BPM);
    } catch(err) {
        res.send(err);
    }
})

Alternatively, without promises, you'll need to use a callback

Using callbacks:

const getPopularArtists = (callback) => {
    const options = {
        url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
        headers: { 'Authorization': 'Bearer ' + access_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'},
        json: true
    }
    
    request.get(options, function(error, response, body) {
        if (error) {
            callback(error);
        } else if (response.statusCode === 200){
            console.log("inside");
            callback(null, getArtistNameIdMap(body, artistNameIdMap));
        } else {
            callback("get popular error");
        }
    })
};

module.exports = {
    GetPopularArtists: getPopularArtists
}

And use it like:

const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", (req, res) =>{
    getPopular.GetPopularArtists((err, artistNameIdMap) => {
        if (err) {
            // handle error here
        } else {
            console.log(artistNameIdMap);
            let BPM = req.params.BPM;
            res.send(BPM);
        }
    });
});

Upvotes: 1

Related Questions