0

I am new to nodeJs. In for loop I am getting array[i] value undefined after get the data from some url. I don't know how to solve this problem. Please help me.

Here is my code

urls =['url1','url2','url3','url4']
 for (var i = 0; i < urls.length; i++) {
  console.log(urls[i]) // getting value
  var opt = {
    url :urls[i],
      headers: {
     'Authorization': 'Bearer '+reply
    } 
   }
  request.get(opt,function(error,response,body) {
     console.log(urls[i]) // getting undefined
     if(!error) {
        enrichment_data.push({type:body});
     } else {
     enrichment_data.push({type:''})
   }
 })
}
3
  • 2
    Change var i to let i for lexical scope. To understand your problem, also try console.log(i) in the problematic location as well. Commented Sep 27, 2017 at 6:47
  • urls[i].url is undefined Commented Sep 27, 2017 at 6:49
  • @PatrickRoberts of course you are right. My mistake Commented Sep 27, 2017 at 6:51

2 Answers 2

5

According to MDN, this type of logical error in understanding JavaScript closures, is a common mistake.

There are two practical ways to solve this. Sticking with ES5 only, the most canonical way to solve this would be to use urls.forEach() instead:

var urls = ['url1', 'url2', 'url3', 'url4']

urls.forEach(function(url, i) {
  console.log(urls[i]) // getting value
  var opt = {
    url: urls[i],
    headers: {
      'Authorization': 'Bearer ' + reply
    }
  }
  request.get(opt, function(error, response, body) {
    console.log(urls[i]) // getting undefined
    if (!error) {
      enrichment_data.push({
        type: body
      });
    } else {
      enrichment_data.push({
        type: ''
      })
    }
  })
})

Using this method, you create a new function scope that preserves the value of each i, even within the asynchronous function, so that the variable reference doesn't get overwritten by later iterations of the for loop you had earlier.

Your second option would be to introduce ES6 lexical scope variable declarations using let like so:

var urls = ['url1', 'url2', 'url3', 'url4']

for (let i = 0; i < urls.length; i++) {
  console.log(urls[i]) // getting value
  var opt = {
    url: urls[i],
    headers: {
      'Authorization': 'Bearer ' + reply
    }
  }
  request.get(opt, function(error, response, body) {
    console.log(urls[i]) // getting undefined
    if (!error) {
      enrichment_data.push({
        type: body
      });
    } else {
      enrichment_data.push({
        type: ''
      })
    }
  })
})

Lexical scope means that any reference to i inside the block scope of the for loop, even within the body of the asynchronous function, will reference that particular iteration of the for loop, allowing it to behave as it appears like it should.

Sign up to request clarification or add additional context in comments.

Comments

0

Great answer by Patrick. I wanted to add few points.

To answer the question, why you are getting undefined at console.log(urls[i]) because the value of i is 4 and nothing is present at index 4.

Now to the point why i is 4. request is an async call and once you call request.get, it goes through event loop and gets written to the stack (with the right url) to be called. . This stack would be called only when the current call is over, which is after your for loop is over. Your loops gets over only when i is 4 and var is global scope

Here is a great video to understand how event loop works.

2 Comments

oh i thought it would be a scope problem : i shouldn't exist outside the loop so it shouldn't exist in the request's console.log()
If I run this const request = require('request'); const urls =['http://www.google.com','http://bing.com','https://duckduckgo.com']; for (var i = 0; i < urls.length; i++) { console.log(urls[i]) // getting value var opt = { url :urls[i] } request.get(opt,function(error,response,body) { console.log(i); if(!error) { console.log('success'); } else { console.log('failure'); } }); } The output is 3 success 3 success 3 success

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.