2012-11-04 11 views
34

私の問題は、node.jsでの非同期プログラミングの理解の欠如に基づいていると確信していますが、ここにはあります。Node.JS:変数を非同期コールバックに渡す方法は?

例:クロールしたいリンクのリストがあります。それぞれの非同期リクエストが返ってくるとき、私はそれがどのURLであるか知りたい。しかし、おそらく競合状態のために、各要求は、リスト内の最後の値に設定されたURLを返します。

var links = ['http://google.com', 'http://yahoo.com']; 
for (link in links) { 
    var url = links[link]; 
    require('request')(url, function() { 
     console.log(url); 
    }); 
} 

予想される出力:

http://google.com 
http://yahoo.com 

実際の出力:

http://yahoo.com 
http://yahoo.com 

だから私の質問はどちらかである:

  1. はどのように(値で)URLを渡しますコールバック機能? OR
  2. HTTPリクエストを連鎖して順次実行する適切な方法は何ですか? OR
  3. 他に何か不足していますか?

PS:私はコールバックのパラメータを調べるソリューションは望んでいませんが、コールバックの一般的な方法は「上からの変数」を知っています。

答えて

46

urlループの範囲は、グローバルと関数のスコープのみをサポートするため、forループのスコープにはなりません。ループの途中でrequireを埋め込むことは良くありません、ところで

var links = ['http://google.com', 'http://yahoo.com']; 
for (link in links) { 
    (function(url) { 
     require('request')(url, function() { 
      console.log(url); 
     }); 
    })(links[link]); 
} 

:だから、すぐに機能を使用して、ループの各反復でurl値をキャプチャするためにあなたのrequest呼び出しのための関数スコープを作成する必要があります練習。この問題の一般的な議論のために

var request = require('request'); 
var links = ['http://google.com', 'http://yahoo.com']; 
for (link in links) { 
    (function(url) { 
     request(url, function() { 
      console.log(url); 
     }); 
    })(links[link]); 
} 
+3

これは範囲についてのものではありません。それは閉鎖についてです。他の多くの言語にはブロックスコープはありませんが、クロージャがないためにこの問題に直面しません。 – slebetman

+3

JavaScriptがブロックスコープをサポートしていれば、OPコードのコールバック関数の 'url'へのクロージャーアクセスは、ループの各反復が(C#のように)独自の' url'変数を取得するので機能します。 – JohnnyHK

+1

要求は簡潔にするためにそこにあります。私のコードでは、すべてが最初に必要です。 – Marc

8

参照https://stackoverflow.com/a/11747331/243639:それはおそらくとして再記述する必要があります。

私は

var links = ['http://google.com', 'http://yahoo.com']; 

function createCallback(_url) { 
    return function() { 
     console.log(_url); 
    } 
}; 

for (link in links) { 
    var url = links[link]; 
    require('request')(url, createCallback(url)); 
} 
+0

StackOverflowに問題を説明するためのリンクがたくさんあります。たとえば、次のようになります。http://stackoverflow.com/questions/3572480/please-explain-theuse-of-javascript-closures-in-loops/3572616#3572616 – slebetman

8

チェックこのblogアウトのようなものをお勧めしたいです。変数は.bind()メソッドを使用して渡すことができます。あなたの場合は次のようになります:

var links = ['http://google.com', 'http://yahoo.com']; 
for (link in links) { 
var url = links[link]; 

require('request')(url, function() { 

    console.log(this.urlAsy); 

}.bind({urlAsy:url})); 
} 
+1

私はこの方法が嫌いです。関数に何かをラップする。 –

関連する問題