我不清楚在nodeJS中如何允许进程更新,例如:
var cancelled = false;
setTimeout(() => cancelled = true,1000);
function main()
{
var ret = []
var totalStart =Date.now();
for(var i=0;i<20;i++) {
var v
var start = Date.now();
while((Date.now()-start)<100)
{
v = Math.sqrt(Math.random());
}
ret.push(v);
if(cancelled) break;
}
console.log("delta:"+(Date.now()-totalStart));
return ret;
}
var r = main()
console.log(r.length)
程序在2000毫秒后结束,但是由于超时,它应该在1000毫秒后结束...什么无法正常工作?
答案 0 :(得分:0)
setTimeout
是异步的。这意味着,除其他外,事件循环在堆栈为空之前不会将其处理程序放在队列中。
因此,setTimeout
需要两个条件才能将其处理程序放入队列(也就是运行它):
1. setTimeout
通话过去了一秒钟。
2.堆栈为空。
这两个条件是强制性的。 setTimeout(handler, 1000)
确保您的处理程序一秒钟之内不会被调用,但完全不能确保它会在一秒钟后立即运行。
另一方面,for和while循环正在阻塞,即,它们不允许事件循环将事物放置到堆栈中。因此,在for循环停止之前,不会调用您的处理程序。
还有另一个与您非常相似的问题,肯定会为您提供帮助:Why does a while loop block the event loop?
但是我不认为这完全是重复的,并且一些额外的解释确实会对您有所帮助。
这则有关事件循环的youtube视频确实帮助我了解了以下内容:https://www.youtube.com/watch?v=8aGhZQkoFbQ
此nodejs文档文章也很不错:https://nodejs.org/ja/docs/guides/dont-block-the-event-loop/
答案 1 :(得分:0)
来自MDN docs
时间值表示(最小)延迟,在该延迟之后,消息实际上将被推送到队列中。如果队列中没有其他消息,则在延迟后立即处理该消息;但是,如果有消息,则setTimeout消息将不得不等待其他消息被处理。因此,第二个参数表示最短时间而不是保证的时间。
由于您的 for循环阻止了主线程,因此直到循环结束,才会处理setTimeout中的消息。
因此0
的超时也将为您提供相同的输出。
setTimeout(() => cancelled = true, 0);
答案 2 :(得分:0)
经过一些测试,这段代码对我来说可以接受。
function AsyncLoop(start,to,fn,endFn) {
return new Promise((resolve, reject) => {
function Step(i) {
var willContinue = fn(i);
if(i==to || !willContinue) {
if(endFn)
endFn(resolve, reject);
else
resolve();
return;
}
setImmediate(Step.bind(null,i+1));
}
Step(start);
});
}
var cancelled = false;
setTimeout(() => { console.log("cancel"); cancelled = true},1100);
var totalStart =Date.now();
var ret=[];
AsyncLoop(0,20, (idx) => {
var start = Date.now();
while((Date.now()-start)<100) {
v=Math.sqrt(Math.random());
}
ret.push(v);
console.log("step "+idx+":"+v);
return !cancelled;
}, (res)=>{
res(ret);
return
}).then((r)=>{
console.log("delta:"+(Date.now()-totalStart));
console.log(r.length)
});