2

It's not clear to me how is it possible in nodeJS to allow the process update, for example:

    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)

The programs ends after 2000ms but, because of the timeout, it should finish after 1000ms... What is not working properly?

Perry
  • 1,113
  • 2
  • 10
  • 22
  • Possible duplicate of [In a While loop setTimeout not working](https://stackoverflow.com/questions/44486075/in-a-while-loop-settimeout-not-working) – lux May 09 '19 at 14:38
  • still no answer, Why node does not have a simple way to convert sync function to async, maybe adding a function like DoEvents() ? – Perry Aug 02 '19 at 08:10
  • `setTimeout` does not say "stop every thread and immediately run my timeout callback when the timeout is up", it simply says "this is the minimum time I should wait until trying to execute the callback once the event loop has processing time." `for` statements are blocking, `while loops are blocking`. – lux Aug 02 '19 at 14:00

3 Answers3

1

From MDN docs

The time value represents the (minimum) delay after which the message will actually be pushed into the queue. If there is no other message in the queue, the message is processed right after the delay; however, if there are messages, the setTimeout message will have to wait for other messages to be processed. For that reason, the second argument indicates a minimum time and not a guaranteed time.

Since your for loop is holding up the main thread, the message from setTimeout is not processed till the loop ends.

So timeout of 0 also gives you the same output.

setTimeout(() => cancelled = true, 0);
1565986223
  • 6,420
  • 2
  • 20
  • 33
0

setTimeout is asynchronous. This means, among other things, that the event loop won't put its handler on the queue until the stack is empty.

So, setTimeout needs two conditions to put its handler on the queue (a.k.a. run it): 1. One second elapsed from the setTimeout call. 2. The stack being empty.

The two conditions are mandatory. setTimeout(handler, 1000) ensures your handler won't be called before one second, but don't ensure at all that it will run after exactly one second.

On the other hand, for and while loops are blocking, i.e. they don't allow the event loop to place things onto the stack. Therefore, your handler is not being called until the for loop stops.

There is another question pretty similar to yours, that will surely help you: Why does a while loop block the event loop?

However I don't think this is exactly a duplicate, and that some extra explanation really will help you.

This youtube video about the event loop really helped me understanding this stuff: https://www.youtube.com/watch?v=8aGhZQkoFbQ

Also this nodejs docs article is pretty good: https://nodejs.org/ja/docs/guides/dont-block-the-event-loop/

Sergeon
  • 6,638
  • 2
  • 23
  • 43
0

After some tests, this code works in an acceptable way for me.

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)   
 });
Perry
  • 1,113
  • 2
  • 10
  • 22