ScrumMaster Guy
ScrumMaster Guy

Reputation: 267

Wait for nodeJs async/promise process to end before sending response to client

I have the following code that I cannot figure out what I need to do to make this entire process finish before sending a response back to the client. Basically I am looking for the client to receive a response once everything in the method completes or errors out, not before.

I have tried several things, moving things around and adding some .then() and .catch() blocks that may not even be needed. I'm still fairly new to NodeJs so while I understand how things kind of work, I still have not got used to asynchronous coding.

let markStepsComplete = async function() {

let stepsToProcess = new Multimap();//multimap JS npm
let results = await dbUtils.getCompletedSteps();
results.forEach(result => {
    stepsToProcess.set(result.ticket_id, result.step_id);
});
return new Promise((resolve,reject)=>{
    stepsToProcess.forEachEntry(async function(entry, key) {
        let payload = {
            ticketId: key,
            stepIds: entry
        }
        let response = await updateStep(payload)//returns promise
            if (response.statusCode === 200) {
                await Promise.all(payload.stepIds.map(async (stepId) => {
                    try {
                        await dbUtils.markStepsCompleted(stepId, payload.ticketId);
                    } catch(err) {
                        reject(err);
                    }
                }));
            }
            else {
                await Promise.all(payload.stepIds.map(async (stepId) => {
                try {
                    await dbUtils.markStepsProcessed(stepId, payload.ticketId, response.statusCode);
                } catch(err) {
                    console.log(err);
                    reject(err);    
                }
                }));

            }


    });
    resolve('Steps Marked Complete');  


});//promise end



}

This is the path that i am testing right now that's making the call to the above method. The updateStep() method is the method that actually calls a HTTP request to an outside REST API. That seems to be working returning a promise.

app.use('/api/posts',async (req,res,next)=>{

let data = await markStepsComplete.markStepsComplete()
.then((data)=>{
    res.status(200).json({message: data})
})
.catch((e)=>{
    console.log('error from catch:',e);
})

})

The code above runs and does run some stuff in our database as part of this process, but I get back the "Steps Marked Complete" resolve message before the process finishes. Since the resolve is hit before the process ends, I can never get any of the reject() errors to come back to the client since resolve is called already.

Thanks in advance.

Upvotes: 0

Views: 1811

Answers (1)

LostJon
LostJon

Reputation: 2387

I noticed this snippet and wanted to call it out because it wont work:

payload.stepIds.forEach(async (stepId) => {
  try {
    await dbUtils.markStepsProcessed(stepId, payload.ticketId, response.statusCode);
  } catch(err) {
    console.log(err);
    reject(err);    
  }
});

when looping through an array of items that require an async fetch, you can do something like:

await Promise.all(payload.stepIds.map(async (stepId) => {
  try {
    await dbUtils.markStepsProcessed(stepId, payload.ticketId, response.statusCode);
  } catch(err) {
    console.log(err);
    reject(err);    
  }
}));

Upvotes: 2

Related Questions