Node.js 循环中的 setTimeout

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15682524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:02:23  来源:igfitidea点击:

setTimeout in Node.js loop

javascriptnode.jsasynchronoussettimeout

提问by glasspill

I'm a bit confused as to how setTimeoutworks. I'm trying to have a setTimeoutin a loop, so that the loop iterations are, say, 1s apart. Each loop iteration makes an HTTP request and it seems like the server on the other end can't handle that many requests in such a short time span.

我对如何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);
};

Why does this not work and how can I achieve this?

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

Thank you

谢谢

采纳答案by bart s

You need something like this

你需要这样的东西

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

See also this fiddle

另见这个小提琴

At the point of the alert(count);you can do your call to the server. Note that the counter works opposite (counting down). I updated with some comments where to do your thing.

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

回答by Yves M.

setTimeoutis non blocking, it is asynchronous. You give it a callback and when the delay is over, your callback is called.

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

Here are some implementations:

下面是一些实现:

Using recursion

使用递归

You can use a recursive callin the setTimeoutcallback.

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

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

  setTimeout(function() {

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

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

Here is how to use your function:

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

waitAndDo(2000); // Do it 2000 times

About stack overflow errors: setTimeoutclear the call stack (see this question) so you don't have to worry about stack overflow on setTimeoutrecursive calls.

关于堆栈溢出错误setTimeout清除调用堆栈(请参阅此问题),因此您不必担心setTimeout递归调用时的堆栈溢出。

Using generators (io.js, ES6)

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

If you are already using io.js(the "next" Node.js that uses ES6) you can solve your problem without recursion with an elegant solution:

如果您已经在使用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');
  }
}

Here is how to use your function (with co):

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

var co = require('co');

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

BTW: This is really using a loop ;)

顺便说一句:这真的是在使用循环 ;)

Generator functions documentation.

生成器函数文档

回答by jmar777

Right now you're scheduling all of your requests to happen at the same time, just a second after the script runs. You'll need to do something like the following:

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

var numRequests = 2000,
    cur = 1;

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

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

    cur++;
    setTimeout(scheduleRequest, 1000)
}

Note that each subsequent request is only scheduled after the current one completes.

请注意,每个后续请求仅在当前请求完成后安排。

回答by Evan Knowles

You're calling makeRequest() in your setTimeout call - you should be passing the function to setTimeout, not calling it, so something like

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

setTimeout(makeRequest, 1000);

without the ()

没有 ()

回答by Sean

I'm surprised that no one has mentioned this above, but it sounds like you need setInterval not setTimeout.

我很惊讶上面没有人提到这一点,但听起来您需要 setInterval 而不是 setTimeout。

vat poller = setInterval(makeRequestFunc, 3000)

The code above will make a request every 3 seconds. Since you saved the object to the variable poller, you can stop polling by clearing the object like so:

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

cleanInterval(poller)

回答by user3444748

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

回答by Ahmad Maleki

I might be late at the party but here is another (more readable) solution without the need to omit forloop.

我可能在聚会上迟到了,但这是另一个(更易读的)解决方案,无需省略for循环。

What your code does is creating 2000 (actually 1999) setTimeoutobjects that will call the makeRequestfunction after 1 second from now. See, none of them knows about the existence of the other setTimeouts.

你的代码不会是创建2000(实际1999)setTimeout对象,这将调用makeRequest1秒后功能从现在开始。看,他们中没有人知道其他setTimeouts的存在。

If you want them 1 sec apart from each other, you are responsible for creating them so.

如果您希望它们彼此相距 1 秒,则您有责任如此创建它们。

This can be achieve by using your counter(in this case i) and the timeout delay.

这可以通过使用您的计数器(在本例中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
};

The first timeout object will be set for 1 secondfrom now and the second one will be set for 2 secondsfrom now and so on; Meaning 1 secondapart from each other.

第一个超时对象将从现在开始设置为1 秒第二个将从现在开始设置为2 秒,依此类推;意思是彼此相隔1 秒