【问题标题】:Node.js callback within a loop has wrong iterator value [duplicate]循环内的Node.js回调具有错误的迭代器值[重复]
【发布时间】:2016-07-23 04:59:20
【问题描述】:

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 作为参数传递给回调函数吗?

【问题讨论】:

  • 因为循环在所有异步操作完成之前完成 - 所有is 将设置为最后一个数字。您需要将异步代码包装在 IIFE 中(例如)

标签: javascript node.js asynchronous callback


【解决方案1】:

您需要使用闭包来正确实现这一点。例如,类似这样的事情。

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

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

【讨论】:

    【解决方案2】:

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

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

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

    所以,您实际上有一个变量 i,它会更新 6 次,最终更新为 i = 6

    您的request() 回调是异步,当您的第一个回调实际被调用时,循环早已消失,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);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-07-10
      • 2023-03-27
      • 2011-11-13
      • 1970-01-01
      • 2014-01-11
      • 1970-01-01
      • 2016-08-27
      • 1970-01-01
      • 2018-09-12
      相关资源
      最近更新 更多