web-dev-qa-db-ja.com

Node.jsループのsetTimeout

setTimeoutがどのように機能するかについて少し混乱しています。ループ内にsetTimeoutを入れようとしているので、ループの反復は、たとえば1秒離れています。ループが繰り返されるたびにHTTPリクエストが作成され、相手側のサーバーはこのような短い時間内にそれほど多くのリクエストを処理できないようです。

for (var i = 1; i<=2000 && ok; i++) {
    var options = {
        Host:'www.Host.com',
        path:'/path/'+i
    };

    setTimeout(makeRequest(options, i), 1000);
};

なぜこれが機能しないのですか?どうすればこれを達成できますか?

ありがとうございました

14
glasspill

あなたはこのようなものが必要です

_var counter = 5;

function makeRequst(options, i) {
    // do your request here
}

function myFunction() {
    alert(counter);

    // create options object here
    //var options = {
    //    Host:'www.Host.com',
    //    path:'/path/'+counter
    //};
    //makeRequest(options, counter);

    counter--;
    if (counter > 0) {
        setTimeout(myFunction, 1000);    
    }
}
_

参照 このフィドル

alert(count);の時点で、サーバーへの呼び出しを行うことができます。カウンターは反対に機能することに注意してください(カウントダウン)。私はあなたのことをどこで行うべきかいくつかのコメントで更新しました。

8
bart s

setTimeout非ブロッキングであり、非同期です。あなたはそれにコールバックを与え、遅延が終わるとあなたのコールバックが呼び出されます。

いくつかの実装は次のとおりです。

再帰の使用

setTimeoutコールバックで 再帰呼び出し を使用できます。

function waitAndDo(times) {
  if(times < 1) {
    return;
  }

  setTimeout(function() {

    // Do something here
    console.log('Doing a request');

    waitAndDo(times-1);
  }, 1000);
}

関数の使用方法は次のとおりです。

waitAndDo(2000); // Do it 2000 times

スタックオーバーフローエラーについてsetTimeout呼び出しスタックをクリアする( この質問 を参照)ので、 setTimeout再帰呼び出しでのスタックオーバーフローについて心配する必要があります。

ジェネレーターの使用(io.js、ES6)

すでに io.jsES6 を使用する「次の」Node.js)を使用している場合は、洗練されたソリューションを使用して、再帰せずに問題を解決できます。

function* waitAndDo(times) {
  for(var i=0; i<times; i++) {

    // Sleep
    yield function(callback) {
      setTimeout(callback, 1000);
    }    

    // Do something here
    console.log('Doing a request');
  }
}

関数の使用方法は次のとおりです( co を使用):

var co = require('co');

co(function* () {
  yield waitAndDo(10);
});

ところで:これは実際にループを使用しています;)

ジェネレーター関数のドキュメント

12
Yves M.

現在、スクリプトの実行からわずか1秒後に、すべてのリクエストが同時に発生するようにスケジュールしています。次のようなことをする必要があります。

var numRequests = 2000,
    cur = 1;

function scheduleRequest() {
    if (cur > numRequests) return;

    makeRequest({
        Host: 'www.Host.com',
        path: '/path/' + cur
    }, cur);

    cur++;
    setTimeout(scheduleRequest, 1000)
}

後続の各リクエストは、現在のリクエストが完了した後にのみスケジュールされることに注意してください。

3
jmar777

上記で誰もこれについて言及していないことに驚いていますが、setTimeoutではなくsetIntervalが必要なようです。

vat poller = setInterval(makeRequestFunc, 3000)

上記のコードは、3秒ごとにリクエストを行います。オブジェクトを変数pollerに保存したので、次のようにオブジェクトをクリアすることでポーリングを停止できます。

cleanInterval(poller)
1
Sean

SetTimeout呼び出しでmakeRequest()を呼び出しています-関数を呼び出すのではなく、setTimeoutに関数を渡す必要があります。

setTimeout(makeRequest, 1000);

()なし

1
Evan Knowles

私はパーティーに遅れるかもしれませんが、ここにforループを省略する必要のない別の(より読みやすい)解決策があります。

あなたのコードが行うことは、1秒後にsetTimeout関数を呼び出す2000(実際には1999)のmakeRequestオブジェクトを作成することですfrom now。ほら、他のsetTimeoutsの存在を知っている人はいません。

それらを互いに1秒離したい場合は、そのように作成する責任があります。

これは、counter(この場合はi)とタイムアウトを使用して実現できますdelay

for (var i = 1; i<=2000 && ok; i++) {
    var options = {
        Host:'www.Host.com',
        path:'/path/'+i
    };

    setTimeout(makeRequest(options, i), i * 1000); //Note i * 1000
};

最初のタイムアウトオブジェクトは今から1秒に設定され、2番目のオブジェクトは2秒に設定されますこれからなど。意味1秒互いに離れている。

0
Ahmad Maleki