循环中的Node.js回调具有错误的迭代器值

Node.js callback within a loop has wrong iterator value

本文关键字:有错误 迭代器 js Node 循环 回调      更新时间:2023-11-21

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

为什么每次触发请求调用后,回调函数中的迭代器值i总是等于6?它使我的TickerToCIK地图的密钥始终是CVX。我需要将I作为参数传递给回调函数吗?

var很棘手:)JavaScript实际上是这样评估代码的:

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

意思是,这就像在第一行代码之前执行的var定义。

因此,您实际上有一个变量i,它被更新了6次,最终更新为i = 6

您的request()回调是async,当您的第一个回调被实际调用时,循环早已结束,i等于6。

解决方案:

一种可能的解决方案是使用IIFE(立即调用函数表达式)。

即:

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

像这样:

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);
}

您需要使用闭包来正确实现这一点。例如,像这样的东西。

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)    
}

我还没有测试过上面的内容,但您可以看到我是如何将请求封装在一个函数中,并将迭代器值作为参数传递给该函数的。