【问题标题】:Node.js: allow process update during loopNode.js:允许在循环期间更新进程
【发布时间】:2020-02-05 18:40:50
【问题描述】:

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

【问题讨论】:

  • 仍然没有答案,为什么节点没有简单的方法将同步函数转换为异步,也许添加一个类似 DoEvents() 的函数?
  • setTimeout 没有说“停止每个线程并在超时时间到时立即运行我的超时回调”,它只是说“这是我应该等待的最短时间,直到尝试执行一次回调事件循环有处理时间。” for 语句被阻塞,while loops are blocking

标签: javascript node.js


【解决方案1】:

来自MDN docs

时间值表示消息实际被推入队列的(最小)延迟。如果队列中没有其他消息,则延迟后立即处理该消息;但是,如果有消息,setTimeout 消息将不得不等待其他消息被处理。因此,第二个参数表示最短时间而不是保证时间

由于您的 for 循环 阻塞了主线程,因此来自 setTimeout 的 消息 在循环结束之前不会被处理。

所以0 的超时也会给你同样的输出。

setTimeout(() => cancelled = true, 0);

【讨论】:

    【解决方案2】:

    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 docs文章也不错:https://nodejs.org/ja/docs/guides/dont-block-the-event-loop/

    【讨论】:

      【解决方案3】:

      经过一些测试,这段代码对我来说是可以接受的。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-26
        • 2021-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多