46

私の問題は、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を(値で)渡すにはどうすればよいですか?また
  2. HTTPリクエストを連鎖させて順番に実行する適切な方法は何ですか?また
  3. 私が行方不明になっている他の何か?

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

4

3 に答える 3

49

JavaScriptはグローバルスコープと関数スコープのみをサポートしているurlため、変数はループにスコープされません。したがって、即時関数を使用してループの各反復で値をキャプチャするforために、呼び出しの関数スコープを作成する必要があります。requesturl

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

requireところで、ループの途中にaを埋め込むのは良い習慣ではありません。おそらく次のように書き直す必要があります。

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]);
}
于 2012-11-04T19:11:16.993 に答える
13

このブログをチェックしてください。.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}));
}
于 2016-05-01T20:50:19.963 に答える
7

この問題の一般的な説明については、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));
}
于 2012-11-04T19:15:43.977 に答える