0

for(var i in companyTickerList) {
  console.log('i = ' + i);
  //construct url
  var url = base_url + companyTickerList[i];
  console.log('url = ' + url);
  request(url, function(error, response, xml) {
    if(!error && response.statusCode == 200) {
      //load xml returned from GET to url
      var cik_xml = cheerio.load(xml)
      console.log('i = ' + i);
      //map company ticker symbol to cik value scraped from xml
      TickerToCIK[companyTickerList[i]] = cik_xml('company-info cik').text();
      console.log('TICKER = ' + companyTickerList[i] + ' CIK = ' + cik_xml('company-info cik').text());
    }  
          
}

//CONSOLE LOG OUTPUT
i = 0
http://www.sec.gov/cgi-bin/browse..........SNPS
i = 1
http://www.sec.gov/cgi-bin/browse..........IBM
i = 2
http://www.sec.gov/cgi-bin/browse..........BA
i = 3
http://www.sec.gov/cgi-bin/browse..........GM
i = 4
http://www.sec.gov/cgi-bin/browse..........F
i = 5
http://www.sec.gov/cgi-bin/browse..........C
i = 6
http://www.sec.gov/cgi-bin/browse..........CVX

i = 6
TICKER = CVX CIK = 0000883241
i = 6
TICKER = CVX CIK = 0000037996
i = 6
TICKER = CVX CIK = 0000831001
i = 6
TICKER = CVX CIK = 0000093410
i = 6
TICKER = CVX CIK = 0001467858
i = 6
TICKER = CVX CIK = 0000012927
i = 6
TICKER = CVX CIK = 0000051143

Why is the iterator value i always equivalent to 6 in the callback function after each request call is triggered? It is making the keys for my TickerToCIK map always be CVX. Do I need to pass i as an argument to the callback function?

alexmac
  • 19,087
  • 7
  • 58
  • 69
Nik Kunkel
  • 335
  • 7
  • 14
  • 1
    Because the loop completes before all the async operations have completed - all `i`s will be set to the last number. You need to wrap your async code in an IIFE (for example) – Andy Apr 03 '16 at 18:29

2 Answers2

1

You will need to use a closure to implement this correctly. For example, something like this.

for(var i in companyTickerList) {
  console.log('i = ' + i);
  //construct url
  var url = base_url + companyTickerList[i];
  console.log('url = ' + url);

  function(i){
    request(url, functon(error, response, xml) {
    if(!error && response.statusCode == 200) {
      //load xml returned from GET to url
      var cik_xml = cheerio.load(xml)
      console.log('i = ' + i);
      //map company ticker symbol to cik value scraped from xml
      TickerToCIK[companyTickerList[i]] = cik_xml('company-info cik').text();
      console.log('TICKER = ' + companyTickerList[i] + ' CIK = ' + cik_xml('company-info cik').text());
      }  
    }
  }(i)    
}

I haven't tested the above, but you can see how I wrapped the request in a function, and passed that function the iterator value as an argument.

user2263572
  • 5,435
  • 5
  • 35
  • 57
1

var is tricky :) JavaScript actually evaluates your code like this:

var i;
for(i in companyTickerList) {
  console.log('i = ' + i);
  // ...

meaning, it's like var definition executed before your first line of code.

So, you actually have a variable i which gets updated 6 times and eventually i = 6.

Your request() callback is async, and by the time your first callback actually got invoked, the loop is long gone and i equals 6.

Solution:

One possible solution is to use an IIFE (Immediately-Invoked Function Expression).

That is:

    (function (i) {
        // async code using i 
    })(i);

Like so:

for (var i in companyTickerList) {
    console.log('i = ' + i);
    //construct url
    var url = base_url + companyTickerList[i];
    console.log('url = ' + url);

    (function (i) {

        request(url, function (error, response, xml) {
            if (!error && response.statusCode == 200) {
                //load xml returned from GET to url
                var cik_xml = cheerio.load(xml);
                console.log('i = ' + i);
                //map company ticker symbol to cik value scraped from xml
                TickerToCIK[companyTickerList[i]] = cik_xml('company-info cik').text();
                console.log('TICKER = ' + companyTickerList[i] + ' CIK = ' + cik_xml('company-info cik').text());
            }
        });

    })(i);
}
Yoav Aharoni
  • 2,672
  • 13
  • 18