Node.js:允许在循环期间更新进程

时间:2019-05-09 14:07:28

标签: javascript node.js

我不清楚在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毫秒后结束...什么无法正常工作?

3 个答案:

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