15

私はどのように機能するかについて少し混乱していますsetTimeoutsetTimeoutループの反復が、たとえば 1 秒間隔になるように、ループ内にしようとしています。ループの反復ごとに HTTP 要求が作成され、反対側のサーバーは、このような短い時間で多くの要求を処理できないようです。

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

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

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

ありがとうございました

4

8 に答える 8

14

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.js ( ES6を使用する「次の」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);
});

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

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

于 2015-06-01T14:03:36.250 に答える
8

このようなものが必要です

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);、サーバーへの呼び出しを行うことができます。カウンターは逆に機能することに注意してください (カウントダウン)。私はあなたのことをどこでやるべきかいくつかのコメントで更新しました。

于 2013-03-28T13:11:32.240 に答える
3

現在、スクリプトが実行されてからわずか 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)
}

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

于 2013-03-28T13:21:32.453 に答える
3

私はパーティーに遅れるかもしれませんが、forループを省略する必要のない別の (より読みやすい) ソリューションを次に示します。

コードが行うことは、今から1 秒後に関数setTimeoutを呼び出す 2000 (実際には 1999) オブジェクトを作成することです。ほら、彼らの誰も他の の存在を知りません。makeRequestsetTimeout

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

これは、カウンター(この場合iは ) とタイムアウト遅延を使用して実現できます。

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秒離れていることを意味します。

于 2017-05-08T06:43:10.140 に答える
1

setTimeout 呼び出しで makeRequest() を呼び出しています-関数を呼び出すのではなく、setTimeout に渡す必要があるため、次のようなものです

setTimeout(makeRequest, 1000);

() なし

于 2013-03-28T13:05:22.510 に答える