Node.js循环中的setTimeout

时间:2013-03-28 13:01:47

标签: javascript node.js asynchronous 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);
};

为什么这不起作用,我该如何实现?

谢谢

7 个答案:

答案 0 :(得分:11)

setTimeout 非阻止,它是异步的。你给它一个回调,当延迟结束时,你的回调就会被调用。

以下是一些实现:

使用递归

您可以在setTimeout回调中使用recursive call

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清除调用堆栈(请参阅this question),这样您就不必担心{{1}上的堆栈溢出递归调用。

使用生成器(io.js,ES6)

如果您已经在使用io.js(&#34;下一个&#34;使用ES6的Node.js),您可以使用优雅的解决方案解决您的问题而无需递归:

setTimeout

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

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');
  }
}

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

Generator functions documentation

答案 1 :(得分: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);    
    }
}

另见this fiddle

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

答案 2 :(得分:3)

现在,您正在安排所有请求同时发生,在脚本运行后仅一秒钟。您需要执行以下操作:

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 :(得分:1)

你在setTimeout调用中调用makeRequest() - 你应该将函数传递给setTimeout,而不是调用它,所以像

这样的东西
setTimeout(makeRequest, 1000);

没有()

答案 4 :(得分:1)

我很惊讶没有人提到过这个,但听起来你需要setInterval而不是setTimeout。

vat poller = setInterval(makeRequestFunc, 3000)

上面的代码每隔3秒发出一次请求。由于您将对象保存到变量poller,因此可以通过清除对象来停止轮询:

cleanInterval(poller)

答案 5 :(得分:0)

        let i = 20;
        let p = Promise.resolve(i)
        while (i > 0) {
        (i => {
            p = p.then(() => {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    console.log(i);
                resolve()
                }, 2000)
            })
            })
        })(i)
        i--
        }
        p = p.then(data => console.log('execution ends'))

答案 6 :(得分:0)

我在这个问题上很晚了(像往常一样...;),但是我发现将请求循环到慢速响应API并在没有HTTP 504的情况下获取响应的唯一方法是使用promises。

async function LoadDataFromAPI(myParametersArray) {
    for(var i = 0; i < myParametersArray.length; i++) { 
        var x = await RunOneRequest(myParametersArray[i]); 
        console.log(x); // ok
    }
}

异步函数调用的函数:

function RunOneRequest(parameter) {
    return new Promise(resolve => {
        setTimeout(() => {
            request(parameter, (error, response, body) => {
                // your request
            });
        resolve('ok);
        }, 2000); // 2 secs
    });
}