While loop not terminating even after the 'return'

I am using the while loop to iterate through an array and trying to terminate the loop using the return (I tried foreach before which doesn’t terminate for return but the while loop should terminate with the use of return).

Can someone help me why this is happening?

Here is my code:

req.on("data", async data => {
    let fetchedData = JSON.parse(data.toString())
    let index=0
    while(index<fetchedData.length) {
      const invoice = fetchedData[index]
    // fetchedData.forEach((invoice, index) => {
      console.log('index',index)
      await new Promise((resolve, reject) => {
        db.query(
          `SELECT * FROM payments WHERE invoice_id = '${invoice.id}' and status = 1`,
          (err, results) => {
            if (err) {
              resolve()
              return res.json({
                status: "error",
                message: "something went wrong!",
              })
            } else {
              if (results.length > 0) {
                resolve()
                console.log('returned')
                return res.json({
                  status: "error",
                  message: `Payment is already done for invoice number ${invoice.invoiceNumber} ! Please delete the payment first.`,
                })
              } else if (index == fetchedData.length - 1) {
                for(let i =0; i<fetchedData.length; i++){
                  db.query(`UPDATE invoices SET status = 0 WHERE id = '${fetchedData[i].id}'`, (err, results) => {
                    if (err) {
                      resolve()
                      return res.json({
                        status: "error",
                        message: "something went wrong!",
                      })
                    } else{
                      deletedInvoices.push(fetchedData[i].id)
                      if(i == fetchedData.length - 1){
                        console.log('deleted')
                        return res.json({
                          status: "success",
                          message: "invoice deleted",
                          deletedInvoices: deletedInvoices
                        })
                      }
                      resolve()
                    }
                  })
                }
              }
            }
          }
        )
      })
      index++;
    }
  })

output:
for an array with the length of 2:

index 0

returned

index 1

returned

(it also throws an error because it is sending a response two times!

>Solution :

In short: the return statement applies to the scope of the function that it is in. And your loop is in an outer scope.

Possible solution

You could define another variable in the same scope as you while loop, check it in each iteration, and when you want an inner scope to end the loop, you not only return but also set that variable.

Something like:

// ...
let index=0
let shouldLoopContinue = true
while(shouldLoopContinue && index<fetchedData.length) {
// ...

and:

// ...
if (err) {
  resolve()
  shouldLoopContinue = false
  return res.json({
    status: "error",
    message: "something went wrong!",
  })
}
// ...

And also in any other place that returns and should stop the loop.

Explanation

In your case:

  • the scope you call return from is the callback function passed as a parameter to db.query(...).
  • db.query(...) itself is in the scope of the callback function passed to new Promise(...)
  • … which is in the same scope as your while loop

So when you call return the way you do now, you only end the execution of that inner callback.

Leave a Reply