2016-04-03 1 views
0

Node.jsのコールバックは、間違ったイテレータ値に

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

を持っているのはなぜ各要求の呼び出しがトリガされた後、コールバック関数内6に私は常に同等のイテレータ値はありますか?私のTickerToCIKマップのキーを常にCVXにしています。コールバック関数の引数としてiを渡す必要がありますか?

+1

すべての非同期操作が完了する前にループが完了しているので - すべての 'i'sが最後の番号に設定されます。非同期コードをIIFEにラップする必要があります(たとえば) – Andy

答えて

1

varはトリッキーです:) JavaScriptが実際にこのようにあなたのコードを次のように評価します

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

意味は、それがコードのあなたの最初の行の前に実行var定義のようなものです。

実際には、という変数が6回更新され、最終的にi = 6に更新されます。

あなたrequest()コールバックが非同期であり、時間によって、あなたの最初のコールバックを実際に呼び出されてしまった、ループが長いなくなっているとiは6

に等しいソリューション:

一つの可能​​な解決策がにありますIIFE(Immediately-Invoked Function Expression)を使用してください。

ですので、同様

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

私は上記をテストしていませんが、あなたは、私は関数内で要求を包み、引数としてその関数にイテレータ値を渡す方法を確認することができます。

関連する問題