简体   繁体   中英

Understanding the event loop and partitioning in Node.js

I've read this nice doc guide: https://nodejs.org/en/docs/guides/dont-block-the-event-loop/

And in some part of that article it's being said regarding to complex calculations without blocking the Event Loop:

Suppose you want to do complex calculations in JavaScript without blocking the Event Loop. You have two options: partitioning or offloading. You could partition your calculations so that each runs on the Event Loop but regularly yields (gives turns to) other pending events.

And they gave as an example this code example to calculate the avg of 0 + 1 + 2 +... + n:

function asyncAvg(n, avgCB) {
  // Save ongoing sum in JS closure.
  var sum = 0;
  function help(i, cb) {
    sum += i;
    if (i == n) {
      cb(sum);
      return;
    }

    // "Asynchronous recursion".
    // Schedule next operation asynchronously.
    setImmediate(help.bind(null, i+1, cb));
  }

  // Start the helper, with CB to call avgCB.
  help(1, function(sum){
      var avg = sum/n;
      avgCB(avg);
  });
}

asyncAvg(n, function(avg){
  console.log('avg of 1-n: ' + avg);
});

My questions are:

  1. According to this doc link: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick

The setImmediate will be executed If the poll phase scripts have been scheduled by setImmediate() , then the event loop will end the poll phase and continue to the check phase to execute those scheduled scripts.

but if we are in the recursive step:

function help(i, cb) {
    sum += i;
    if (i == n) {
      cb(sum);
      return;
    }

    // "Asynchronous recursion".
    // Schedule next operation asynchronously.
    setImmediate(help.bind(null, i+1, cb));
  }

then the poll should be empty but the setImmediate command, and therefore it should keep running the recursive, so how would it give opportunity to other code to be executed meanwhile? in terms of event-loop scheduling.

  1. Why for really big n there isn't RangeError: Maximum call stack size exceeded error, but if I change this line:
setImmediate(help.bind(null, i+1, cb));

to this line:

help(i+1, cb);

then the error RangeError: Maximum call stack size exceeded pops up. I mean, using the setImmediate should anyway keep the functions stack caused by the recursive, no?

then the poll should be empty but the setImmediate command, and therefore it should keep running the recursive, so how would it give opportunity to other code to be executed meanwhile?

Because setImmediate schedules callbacks to happen just after the poll phase completes. Those callbacks are run during the check phase. Adding more callbacks during check schedules them, but doesn't cause them to run; that happens the next time the loop gets to the poll phase, sees there are pending callbacks, and enters the check phase.

Why for really big n there isn't RangeError: Maximum call stack size exceeded error

Because the recursion isn't immediate, so it doesn't consume stack space. setImmediate just schedules a callback, it doesn't call the callback. Your code ends, releasing its stack resources, and the event loop continues. Later, the callback you scheduled via setImmediate gets run, briefly using a small bit of stack space.

In contrast, when you call help immediately, that's allocating a new stack frame, and if you use a big n , you allocate too many stack frames and run out of stack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM