1

My Setup: NodeJS, express, mongoose

var i;
for(i = 0; i < results.length; i++){
    console.log("out: "+i);
    RegionData.findOne({'rid': results[i].region_id}, function (err, product) {
        if (product) {
            console.log("in: " + i);
        }
    });
}

The output:

out: 0
out: 1
out: 2
out: 3
in: 4
in: 4
in: 4
in: 4

My expect output:

out: 0
in: 0
out: 1
in: 1
out: 2
in: 2
out: 3
in: 3

I don't know why it is not my expect output, it finishes the "out: i" first then "in: i". Whether is the .findOne problem?

potato
  • 203
  • 2
  • 15
  • That `.findOne()` function is **asynchronous**. The value of `i` when those callbacks are finally invoked will be the value *after* the loop finishes. – Pointy Sep 13 '18 at 14:34
  • If you write that with `.forEach()` instead of a `for` loop, you'll get the output you expect. – Pointy Sep 13 '18 at 14:35
  • See the answer here: https://stackoverflow.com/questions/52276979/looping-result-last-index-of-array/52277033#answer-52277033 – dustytrash Sep 13 '18 at 14:37

2 Answers2

1

use closure:

var i;
for(i = 0; i < results.length; i++){
    (function(i){
        console.log("out: "+i);
        RegionData.findOne({'rid': results[i].region_id}, function (err, product) {
            if (product) {
                console.log("in: " + i);
            }
        });
    })(i)
}

or es6

for(let i = 0; i < results.length; i++){

https://decembersoft.com/posts/understanding-javascript-closures-in-for-loops/

givehug
  • 1,863
  • 1
  • 14
  • 19
0

Use let in your loop. That way each iteration will get a unique value in the closure.

for(let i = 0; i < results.length; i++)

Or use a forEach

results.forEach( (result, index) => { })

This snippet demonstrates both, and verifies that the forEach index is the same as the let.

function getIt() {
  return new Promise((res, rej) => {
    setTimeout(() => {
      res(Math.random())
    }, 1000)
  })
}

var i;
for (let i = 0; i < 4; i++) {
  console.log("out: " + i);
  getIt().then(product => {
    console.log("in: " + i);
  });
}

const items = [1, 2, 3, 4]
items.forEach((item, i) => {
  console.log("out2: " + i);
  getIt().then(product => {
    console.log("in2: " + i);
  });
})
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78