Javascript 在Node.js循环中设置超时

Javascript 在Node.js循环中设置超时,javascript,node.js,asynchronous,settimeout,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 }; setTim

我对
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);
};
for(var i=1;i您正在setTimeout调用中调用makeRequest()——您应该将函数传递给setTimeout,而不是调用它,所以类似于

setTimeout(makeRequest, 1000);

没有()

你需要这样的东西

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

在发出
警报(计数);
时,您可以呼叫服务器。 请注意,计数器的工作方式相反(倒计时)
注释在何处执行操作。

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

var numRequests = 2000,
    cur = 1;

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

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

    cur++;
    setTimeout(scheduleRequest, 1000)
}
请注意,每个后续请求仅在当前请求完成后计划。

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

以下是一些实现:

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

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

  setTimeout(function() {

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

    waitAndDo(times-1);
  }, 1000);
}
关于堆栈溢出错误
setTimeout
清除调用堆栈(请参阅),这样就不必担心递归调用中的堆栈溢出问题

使用生成器(io.js、ES6) 如果您已经在使用(使用的“next”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');
  }
}
顺便说一句:这实际上是在使用循环;)


.

我可能会在聚会上迟到,但这里有另一个(更具可读性的)解决方案,无需省略
for
循环

您的代码所做的是创建2000(实际上是1999)
setTimeout
对象,这些对象将在从现在开始的1秒后调用
makeRequest
函数。看,他们都不知道另一个
setTimeout
s的存在

如果您希望它们彼此间隔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
};

for(var i=1;i我很惊讶上面没有人提到这一点,但听起来您需要的是setInterval而不是setTimeout

vat poller = setInterval(makeRequestFunc, 3000)
上面的代码将每3秒发出一次请求。由于您已将对象保存到变量
poller
,您可以通过如下方式清除对象来停止轮询:

cleanInterval(poller)

我在这个问题上已经很晚了(像往常一样…;),但我发现将请求循环到慢时间响应API并在没有HTTP 504的情况下获得响应的唯一方法是使用承诺

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

欢迎。如果您对服务器的请求不是时间关键型的,则最好使用一种构造,即新的计时器仅在上一个服务器调用完成后启动。然后,即使调用花费的时间超过1秒(setTimeout timer值),也只会有一个服务器调用处于活动状态警告:您的解决方案可能导致
范围错误:超过了最大调用堆栈大小
。请参阅使用
setImmediate
。顺便说一句,OP使用的是Node.js..(Node.js中没有
警报)。@Yves M.:The
setTimeout()
应该足够了。在这个解决方案中没有对
myFunction
的递归调用。@Yves M:我同意,
setTimeout
调用您赋予它的函数,但在节点中,它在事件循环的不同迭代中这样做,因此
myFunction
实际上并不调用自己。例如,直接递归调用fa在20 929次呼叫后为我进行ils。使用setTimeout可以清除50万次呼叫,没有失败的迹象。@MikeTunicLiffe是的,对不起,我的错误:D setTimeout确实清除了呼叫堆栈..对不起。请阅读此::D您的代码没有堆栈溢出…:)这就是我的想法well@jmar777我意识到这是一个老帖子,然而,我有一个类似的问题。您是否介意回答为什么
scheduleRequest
函数不通过
cur
numRequests
cleanInterval(poller)
        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'))
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
    });
}