Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

Notes:

  • Text in [[ ]] are the internal libuv function call.
  • Text in {{ }} are the Node functions that are affected.
  • Text in ( ) are notes about what is happening.
  • While the Windows event loop has minor variations, I don't believe any of those affect Node.

On process.nextTick():

process.nextTick() is poorly named. It doesn't actually wait until the "next tick" of the event loop. Instead it runs any callbacks passed directly after the synchronous execution of the current phase of the event loop (i.e. before the event loop can continue to the next phase).

This translates to the fact that the nextTickQueue (i.e. the mechanism that contains all callbacks passed to process.nextTick() during the execution of any callback) is processed at the end of every phase of the event loop.

This is poorly used in Node in cases like "close" events, where the event is emitted asynchronously but only by means of process.nextTick(). Instead of actually calling the close callback in the final phase of the event loop (uv__run_closing_handles()).

There has been discussion on correcting this, but my initial attempt broke several tests and I haven't taken the time to figure out why.


Brief overview of the current state of the event loop, and what runs at any given time.

              ┌───────────────────────┐
              │  Application Startup  │
              └───────────┬───────────┘
                          │
                          │ (bootstrap global environment)
                          │
              ┌───────────┴───────────┐
              │    [[ uv_run() ]]     │
              └───────────┬───────────┘
                          │
            ┌─────────────┴─────────────┐
       ╭────┤  [[ uv__run_timers()  ]]  │
       │    ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │    ┃    {{ setTimeout() }}     ┃
       │    ┃    {{ setInterval() }}    ┃
       │    ┗━━━━━━━━━━━━━┯━━━━━━━━━━━━━┛
       │                  │
       │    ┌─────────────┴─────────────┐
       │    │  [[ uv__run_pending() ]]  │
       │    ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │    ┃ All completed write reqs. ┃
       │    ┃                           ┃
       │    ┃ Error Reporting for:      ┃
       │    ┃ - TCP ECONNREFUSED        ┃
       │    ┃ - PIPE (all errors)       ┃
       │    ┗━━━━━━━━━━━━━┯━━━━━━━━━━━━━┛
       │                  │
       │    ┌─────────────┴─────────────┐
       │    │   [[ uv__run_idle() ]]    │
       │    ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │    ┃  {{ clearImmediate() }}   ┃
       │    ┗━━━━━━━━━━━━━┯━━━━━━━━━━━━━┛
       │                  │
       │    ┌─────────────┴─────────────┐
       │    │  [[ uv__run_prepare() ]]  │
       │    ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │    ┃    CPU Idle Profiler      ┃
       │    ┃ (Inform V8 profiler that  ┃
       │    ┃  Node is about to idle)   ┃
       │    ┗━━━━━━━━━━━━━┯━━━━━━━━━━━━━┛
       │                  │
       │    ┌─────────────┴─────────────┐
       │    │    [[ uv__io_poll() ]]    │
       │    ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │    ┃(Poll for incoming or      ┃
       │    ┃completed events signaled  ┃
       │    ┃back from the kernel)      ┃
       │    ┃                           ┃
       │    ┗━━━━━━━━━━━━━┯━━━━━━━━━━━━━┛
       │                  │
       │    ┌─────────────┴─────────────┐
       │    │   [[ uv__run_check() ]]   │
       │    ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │    ┃   {{ setImmediate() }}    ┃
       │    ┃                           ┃
       │    ┃    CPU Idle Profiler      ┃
       │    ┃ (Inform V8 profiler that  ┃
       │    ┃  Node is no longer idle)  ┃
       │    ┗━━━━━━━━━━━━━┯━━━━━━━━━━━━━┛
       │                  │
       │  ┌───────────────┴───────────────┐
       │  │[[ uv__run_closing_handles() ]]│
       │  ┢━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┪
       │  ┃(Currently not used by Node as ┃
       ╰──┨all close callbacks are instead┃
          ┃called prior to this via.      ┃
          ┃process.nextTick())            ┃
          ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
@iliakan

This comment has been minimized.

Copy link

iliakan commented Nov 16, 2014

Is this picture still up to date? What does clearImmediate() do in uv__run_idle()? Couldn't find the call in the sources.

@ghost

This comment has been minimized.

Copy link

ghost commented Apr 21, 2016

@iliakan It's been awhile, but if you still care...prepare, check, and idle are all defined via macro. Take a look at uv/src/<win|unix>/loop-watcher.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.