0

I'm self taught in NodeJS and have created a process of:

  • Finding 'claims' requiring an invoice (return array)
  • For each claim in the array, create an invoice
  • After invoice is created update a table ([scripts]) based on the claimID.

Now the code is working and I believe the Async/Await is working so that the invoices are created and attached in the correct order as so far my tests show this is correct.

What I am curious about is:

  • Would this be better phrased as using .THEN or is what I have "acceptable"
  • Why is my console.log showing the claimID's processed in a different order than the array?

The main section in question is the FOREACH section.

My log is as below:

[
  RowDataPacket { ClaimID: 2457 },
  RowDataPacket { ClaimID: 1370 },
  RowDataPacket { ClaimID: 1 },
  RowDataPacket { ClaimID: 1853 },
  RowDataPacket { ClaimID: 2438 }
]
2457
1370
1
1853
2438
Attached invoice 23393 For Claim 2457
Attached invoice 23395 For Claim 1
Attached invoice 23394 For Claim 1370
Attached invoice 23397 For Claim 2438
Attached invoice 23396 For Claim 1853

If the array is in order, then the claimID log number is in order, WHY are the logs for the "invoice created" out of order in Function[createInvoiceAndAttach]?

This doesn't affect my end result, I'm I just want to understand the whole async situation better!

router.post('/generateInvoices/',verify, async (req,res) => {    
    const uploadBody = req.body;
    
    
    const ScrBatchID = uploadBody.ScrBatchID;
    const scriptList = uploadBody.zephyrScripts;
    const invBatchDate = uploadBody.scriptBatchDate;
    
   
    try{
        //Update prices etc on the script table.
        // This function also checks a few other components returning true/false depending on success of the update.
        const updateScriptsSuccess = await updateScripts(scriptList);

        if(!updateScriptsSuccess){
            return res.status(200).json({
                
                Result: false
                
            })  
        }

        //Create an Invoice BATCH - related to todays dateTime.
        const invoiceBatchID = await createInvoiceBatch(invBatchDate,req.user._id);
        console.log(invoiceBatchID);


        //Get an array of the claim ID's
        const claimsToInvoice = await getClaimsToInvoice(ScrBatchID);
        console.log(claimsToInvoice);


        let invoiceUpdateSuccess = false;   

        //For each of the Claim ID's in the array, Create an invoice ID using the invoiceBatchID previously obtained
        //In the subfunction, also add this obtained InvoiceID to the script table
        claimsToInvoice.forEach(async (claim) => {
            let ClaimID = claim.ClaimID;
            console.log(ClaimID);
            invoiceUpdateSuccess = await createInvoiceAndAttach(invoiceBatchID,ClaimID, ScrBatchID);
            
            
            //Return the result of the update.  If any of the subfunctions errored out, they will filter up a FALSE and thus the total success is false.
            if(!invoiceUpdateSuccess){
                return res.status(200).json({
                
                    Result: false
                    
                })  
            } 



        })
        
            
        //If nothing above failed, continue to this section and mark this batch of claims as completed, so they don't get invoiced again.
        const totalSuccess = await updateScriptBatch(ScrBatchID,invBatchDate,req.user._id);

        if(totalSuccess){
            return res.status(200).json({
            
                Result: true
                
            })  
        }else{
            return res.status(200).json({
                
                Result: false
                
            }) 
        }
    }catch (e) {
        // this catches any exception in this scope or await rejection
        console.log(e);
        
        return res.status(500).json({
                
            Result: false
            
        }) 
    } 
});

function createInvoiceAndAttach(invoiceBatchID,ClaimID, ScrBatchID){
    return new Promise(async (resolve,reject) =>{     
        
        
        let InvoiceID = await getInvoiceID(invoiceBatchID);
        //console.log(InvBatchDate);
        if(InvoiceID == 0){
            return reject(false);
        }else{

            try{
            
                //console.log(scriptID + " " + invAmount);
                var sqlString = "SET @InvoiceID = ?; SET @ScrBatchID = ?; SET @ClaimID = ?; Call updateScriptWithInvoiceID(@InvoiceID,@ScrBatchID,@ClaimID);";
                
                connection.query(sqlString,[InvoiceID,ScrBatchID,ClaimID], (err,rows,fields)=>{
                    
                    if(!err){
                        console.log("Attached invoice " + InvoiceID + " For Claim " + ClaimID);
                        return resolve(true);  
        
                    }else{
                        return reject(false);
                    } 
                        
                })
            } catch (e) {
                // this catches any exception in this scope or await rejection
                console.log(e);
                
                return reject(false);
            } 

        }

        
        
    }) 
    
};

function getInvoiceID(InvoiceBatchID){
    return new Promise((resolve,reject) =>{     
        
        

        //console.log(InvBatchDate);
        

        try{
            
            //console.log(scriptID + " " + invAmount);
            var sqlString = "INSERT INTO invoices(InvoiceBatchID) VALUES (?);";
            
            connection.query(sqlString,[InvoiceBatchID], (err,rows,fields)=>{
                
                if(!err){
                    
                    return resolve(rows.insertId);  
    
                }else{
                    return reject(0);
                } 
                    
            })
        } catch (e) {
            // this catches any exception in this scope or await rejection
            console.log(e);
            
            return reject(0);
        } 
        
    })   
};
Glenn Angel
  • 381
  • 1
  • 3
  • 14
  • 1
    As described in [the answer](https://stackoverflow.com/questions/50101875/make-sure-a-foreach-with-async-calls-is-executed-before-another-one/50110131#50110131) your question is marked a duplicate of, `.forEach()` is not promise-aware at all. So, when you give it an `async` callback and use `await` in that callback, the `.forEach()` loop does not wait for the `await`. Instead, it just starts the next iteration of the loop and all the iterations end up running in parallel with random finish order. Get rid of `.forEach()` for all asynchronous programming. Use a regular `for` loop instead. – jfriend00 Apr 14 '22 at 02:42
  • Thanks @jfriend00 . I had a feeling there was something 'basic' i was missing. – Glenn Angel Apr 14 '22 at 04:54

0 Answers0