0
votes

Javascript/Node noob here. Having some trouble with understanding the whole asynchronous aspect of JS. I am building a small app that's purpose is to make calls to an external API and then store the results for logging purposes.

Anyway, I have a GET request that looks like this

request(callsOptions)
.then(function (res) {
    //Request success... do some logic with the response object
    var content = JSON.stringify(res)
    //save result to a file with the name as m-d-yyyy.json
    fs.writeFile(`callLogs/${month}-${day}-${year}.json`, content, 'utf8', function (err) {
        if (err) {
            return console.log(err);
        }
    })        
    //get session_ids and call destinations and store in the 2 diff arrays
    var calls = res.calls
    for(let x = 0; x < calls.length; x++){
        session_ids[x] = calls[x].session_id
        dests[x] = calls[x].dest
    }
    //make an individual req for each call in the array
    for(let x = 0; x < calls.length; x++){
        getCallLog(session_ids[x], dests[x])
    }
}).catch(function (err) {
    //Request failure...
    console.log('Whoops... something went wrong with the calls request!')
})

This then calls the getCallLog method, which takes the info extracted from the previous request and makes a bunch more calls

function getCallLog(id, dest){
request(constructURL(id))
    .then(function (res) {
        //Request success... do some logic with the response object
        console.log('Request success!')
        var content = JSON.stringify(res)
        fs.writeFile(`${dest}/${id}.json`, content, 'utf8', function (err) {
            if (err) {
                return console.log(err);
            }
        })
        //return res
    }).catch(function (err) {
        //Request failure...
        console.log('Whoops... something went wrong with the call request!')
    })

}

So, I want to wait until AFTER all the GET requests have completed to do some logic. For now, that logic will simply be something like

    console.log('DONE')

The problem is everything I've tried will show DONE before its done due to the asynchronous aspect of JS. So, I'm just stuck waiting for a bit to make sure all the requests have finished.

Things I've tried:

  • putting an if statement in the for-loop for when the loop completes
  • using a counter in the getCallLog().then() function

EDIT: like this?

    const { promisify } = require("util")

...

request(callsOptions)
    .then(function (res) {
        //Request success... do some logic with the response object
        var content = JSON.stringify(res)
        //save result to a file with the name as m-d-yyyy.json under the callLogs folder
        fs.writeFile(`callLogs/${month}-${day}-${year}.json`, content, 'utf8', function (err) {
            if (err) {
                return console.log(err);
            }
        })
        //get session_ids and call destinations and store in the 2 diff arrays
        var calls = res.calls
        for (let x = 0; x < calls.length; x++) {
            session_ids[x] = calls[x].session_id
            dests[x] = calls[x].dest
        }
        //make an individual req for each call in the array
        const promises = [];
        for (let x = 0; x < calls.length; x++) {
            promises.push(getCallLog(session_ids[x], dests[x]))
        }
        return Promise.all(promises)
    }).then(function(){
        console.log("All done!")
    }).catch(function (err) {
        //Request failure...
        fs.writeFile(`errorlog/${month}-${day}-${year}.json`, content, 'utf8', function (err) {
            if (err) {
                return console.log(err);
            }
        })
    })

function getCallLog(id, dest){
request(constructURL(id))
    .then(function (res) {
        //Request success... do some logic with the response object 
        console.log('Request success!')
        var content = JSON.stringify(res)
        return promisify(fs.writeFile)(`${dest}/${id}.json`, content, 'utf8');
    }).catch(function (err) {
        //Request failure...
        fs.writeFile(`errorlog/${month}-${day}-${year}-${id}.json`, err, 'utf8', function (err) {
            if (err) {
                return console.log(err);
            }
        })
    })
    }
1

1 Answers

1
votes

Just return a promise from the inner function and promisify the file writing:

const { promisify } = require("util");

function getCallLog(id, dest){
  return request(constructURL(id)) // <-- return the promise
   .then(function (res) {
      //Request success... do some logic with the response object
      console.log('Request success!')
      var content = JSON.stringify(res)
      return promisify(fs.writeFile)(`${dest}/${id}.json`, content, 'utf8');
  }).catch(function (err) { // also catches writing errors
    console.log('Whoops... something went wrong with the call request!')
  });
}

Now you can collect all the promises in.your loop:

const promises = [];
for(let x = 0; x < calls.length; x++){
    promises.push(getCallLog(session_ids[x], dests[x]));
}

And then return these promises into the chain:

return Promise.all(promises);

So now you can add a .then(...) to the chain that will get executed afterwards:

.then(() => console.log("All done!"));