Node.js循环中的setTimeout

gla*_*ill 14 javascript asynchronous settimeout node.js

关于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);
};
Run Code Online (Sandbox Code Playgroud)

为什么这不起作用,我怎样才能做到这一点?

谢谢

Yve*_* M. 12

setTimeout非阻塞的,它是异步的.你给它一个回调,当延迟结束时,你的回调被调用.

以下是一些实现:

使用递归

您可以在回调中使用递归调用setTimeout.

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

  setTimeout(function() {

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

    waitAndDo(times-1);
  }, 1000);
}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用您的功能:

waitAndDo(2000); // Do it 2000 times
Run Code Online (Sandbox Code Playgroud)

关于堆栈溢出错误: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');
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用您的函数(与co):

var co = require('co');

co(function* () {
  yield waitAndDo(10);
});
Run Code Online (Sandbox Code Playgroud)

BTW:这实际上是在使用一个循环;)

生成器功能文档.


bar*_*t s 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);    
    }
}
Run Code Online (Sandbox Code Playgroud)

另见这个小提琴

此时,alert(count);您可以拨打服务器.请注意,计数器的工作方式相反(倒计时).我更新了一些评论在哪里做你的事情.

  • @Yves M.:我同意,`setTimeout`调用你给它的函数,但是在Node中它在事件循环的不同迭代中这样做,所以`myFunction`实际上并不调用它自己.例如,在20 929次调用后,对我进行直接递归调用失败.使用setTimeout,它清除了50万个呼叫而没有失败的迹象. (3认同)