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.:ThesetTimeout()
应该足够了。在这个解决方案中没有对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
});
}