haxetink / tink_core

Core utilities
https://haxetink.github.io/tink_core
MIT License
117 stars 33 forks source link

`Callback.defer` on nodejs, `nextTick` or `setImmediate`? #156

Closed kevinresol closed 3 years ago

kevinresol commented 3 years ago

TIL that nextTick essentially inserts the callback at the head of the event queue, so the callback will be executed right after the current event. While setImmediate will insert the callback at the tail of the event queue, so it will be invoked after all the already-queued events.

As a result, when used recursively nextTick will always occupy the queue head thus "blocking" other events such as Timers:

setInterval(() => console.log('timer'), 0); // this will never fire
(function loop() {
  console.log('loop');
  process.nextTick(loop);
})();

In conclusion I think setImmediate is a safer option for Callback.defer

Edit: I guess I see why nextTick might be preferred here, if its major intention is to mitigate stack overflow while trying to execute the rest ASAP. In that case I think we should document it because it is inconsistent across platforms. Note that on non-node JS Promise.resolve().then(loop) should have the same effect.

back2dos commented 3 years ago

A "hybrid" approach would avoid blocking the loop. Sketch:

static var currentlyBlocking = false;
static public function defer(f) 
  if (isBlocking) deferNonBlocking(f);
  else deferBlocking(() -> {
      currentlyBlocking = true;
      f();
      currentlyBlocking = false;
  });

That being said, I don't think I feel strongly about using nextTick, so I'm inclined to think setImmediate is the best option for the sake of consistency.