-1

For loop in node.js is behaving quite weirdly. code is as below:

for(var i = 0; i < req.body.stages.length; i++){
    if (req.body.current_stage == req.body.stages[i].stage_short_desc){
        console.log('value of i :'+ i)
        Application.findOne({ application_num: req.params.id }, (error, application) => {
            if (error) {
                logger.error('Application not found' + error)
            } else {
                console.log('reached here : ' + i)
                console.log(req.body.stages[i].requisites.length)
                ....
            }
        })

    }
}

And result is:

value of i :0 reached here : 8 error: uncaughtException: Cannot read property 'requisites' of undefined.

req.body.current_stage == req.body.stages[i].stage_short_desc ---> happens at i = 0

I am surprised, when index i was 0, it is entering into if loop and satisfies the condition, hence first line of result. Then find the application from database, if successful then if we notice value of index i is 8 (which is maximum value of index). Can anyone please suggest how this is possible?

Thanks!

Mohit Aggarwal
  • 113
  • 3
  • 14
  • Is it possible that req.body.stages is being changed (for example inside Application.findOne)? It might be helpful for you to log out the length of req.body.stages inside the callback function of Application.findOne. The callback might also be taking place after the loop has terminated. – Fridjon Gudjohnsen Jul 29 '18 at 21:29
  • Change `for (var i = 0, ...)` to `for (let i = 0, ...)`. `let` will make a unique instance of `i` for each invocation of the loop so when the `Application.findOne()` callback gets called asynchronously, long after the loop has finished, you will have the right `i`. – jfriend00 Jul 29 '18 at 23:12

2 Answers2

0

The for loop continues to run instantly, while the findOne is executed asynchronously for each step of the loop. When the callback for each findOne is called, the loop has already finished, hence i is 8 at that point, every time.

Patrick Hund
  • 19,163
  • 11
  • 66
  • 95
0

This happens because you're trying to execute an asynchronous code involving callbacks inside a synchronous piece of code. For your code to work the way intended, you may promisify the mongoose methods, and then push that into an array of promises that you may choose to resolve later :

const promises = [];

for (let i = 0; i < req.body.stages.length; i++) {
    if (req.body.current_stage == req.body.stages[i].stage_short_desc) {
        console.log('value of i :' + i);
        // Don't forget to promisify mongoose methods
        promises.push(Application.findOne({ application_num: req.params.id }));
    }
}

Promise.all(promises).then((application) => {
    // Do your magic here
}).catch((err) => {
    // Again your magic
})
nerdier.js
  • 591
  • 1
  • 4
  • 15