Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ order of operations.

```
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ timers │
└─────────────┬─────────────┘
v
┌───────────────────────────┐
┌─>│ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
Expand All @@ -44,7 +46,10 @@ order of operations.
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
│ │ close callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ timers │
└───────────────────────────┘
```

Expand Down Expand Up @@ -73,16 +78,17 @@ longer than a timer's threshold. See the [**timers**](#timers) and

## Phases Overview

- **timers**: this phase executes callbacks scheduled by `setTimeout()`
and `setInterval()`.
- **pending callbacks**: executes I/O callbacks deferred to the next loop
iteration.
- **idle, prepare**: only used internally.
- **poll**: retrieve new I/O events; execute I/O related callbacks (almost
all with the exception of close callbacks, the ones scheduled by timers,
and `setImmediate()`); node will block here when appropriate.
- **check**: `setImmediate()` callbacks are invoked here.
- **close callbacks**: some close callbacks, e.g. `socket.on('close', ...)`.
- **close callbacks**: some close callbacks, e.g. `socket.on('close', ...)`
- **timers**: this phase executes callbacks scheduled by `setTimeout()`
and `setInterval()`. Additionally, these callbacks can execute before entering the event loop.
This sometimes happens for setTimeout(() => { ... }, 0) outside the I/O loop.

Between each run of the event loop, Node.js checks if it is waiting for
any asynchronous I/O or timers and shuts down cleanly if there are not
Expand All @@ -95,6 +101,66 @@ and how they interact with timers in certain scenarios.

## Phases in Detail

### pending callbacks

This phase executes callbacks for some system operations such as types
of TCP errors. For example if a TCP socket receives `ECONNREFUSED` when
attempting to connect, some \*nix systems want to wait to report the
error. This will be queued to execute in the **pending callbacks** phase.

### poll

The **poll** phase has two main functions:

1. Calculating how long it should block and poll for I/O, then
2. Processing events in the **poll** queue.

When the event loop enters the **poll** phase _and there are no timers
scheduled_, one of two things will happen:

- _If the **poll** queue **is not empty**_, the event loop will iterate
through its queue of callbacks executing them synchronously until
either the queue has been exhausted, or the system-dependent hard limit
is reached.

- _If the **poll** queue **is empty**_, one of two more things will
happen:
- If scripts have been scheduled by `setImmediate()`, the event loop
will end the **poll** phase and continue to the **check** phase to
execute those scheduled scripts.

- If scripts **have not** been scheduled by `setImmediate()`, the
event loop will wait for callbacks to be added to the queue, then
execute them immediately.

Once the **poll** queue is empty the event loop will check for timers
_whose time thresholds have been reached_. If one or more timers are
ready, the event loop will wrap back to the **timers** phase to execute
those timers' callbacks.

### check

This phase allows the event loop to execute callbacks immediately after the
**poll** phase has completed. If the **poll** phase becomes idle and
scripts have been queued with `setImmediate()`, the event loop may
continue to the **check** phase rather than waiting.

`setImmediate()` is actually a special timer that runs in a separate
phase of the event loop. It uses a libuv API that schedules callbacks to
execute after the **poll** phase has completed.

Generally, as the code is executed, the event loop will eventually hit
the **poll** phase where it will wait for an incoming connection, request,
etc. However, if a callback has been scheduled with `setImmediate()`
and the **poll** phase becomes idle, it will end and continue to the
**check** phase rather than waiting for **poll** events.

### close callbacks

If a socket or handle is closed abruptly (e.g. `socket.destroy()`), the
`'close'` event will be emitted in this phase. Otherwise it will be
emitted via `process.nextTick()`.

### timers

A timer specifies the **threshold** _after which_ a provided callback
Expand Down Expand Up @@ -182,65 +248,6 @@ be 105ms.
> also has a hard maximum (system dependent) before it stops polling for
> more events.

### pending callbacks

This phase executes callbacks for some system operations such as types
of TCP errors. For example if a TCP socket receives `ECONNREFUSED` when
attempting to connect, some \*nix systems want to wait to report the
error. This will be queued to execute in the **pending callbacks** phase.

### poll

The **poll** phase has two main functions:

1. Calculating how long it should block and poll for I/O, then
2. Processing events in the **poll** queue.

When the event loop enters the **poll** phase _and there are no timers
scheduled_, one of two things will happen:

- _If the **poll** queue **is not empty**_, the event loop will iterate
through its queue of callbacks executing them synchronously until
either the queue has been exhausted, or the system-dependent hard limit
is reached.

- _If the **poll** queue **is empty**_, one of two more things will
happen:
- If scripts have been scheduled by `setImmediate()`, the event loop
will end the **poll** phase and continue to the **check** phase to
execute those scheduled scripts.

- If scripts **have not** been scheduled by `setImmediate()`, the
event loop will wait for callbacks to be added to the queue, then
execute them immediately.

Once the **poll** queue is empty the event loop will check for timers
_whose time thresholds have been reached_. If one or more timers are
ready, the event loop will wrap back to the **timers** phase to execute
those timers' callbacks.

### check

This phase allows the event loop to execute callbacks immediately after the
**poll** phase has completed. If the **poll** phase becomes idle and
scripts have been queued with `setImmediate()`, the event loop may
continue to the **check** phase rather than waiting.

`setImmediate()` is actually a special timer that runs in a separate
phase of the event loop. It uses a libuv API that schedules callbacks to
execute after the **poll** phase has completed.

Generally, as the code is executed, the event loop will eventually hit
the **poll** phase where it will wait for an incoming connection, request,
etc. However, if a callback has been scheduled with `setImmediate()`
and the **poll** phase becomes idle, it will end and continue to the
**check** phase rather than waiting for **poll** events.

### close callbacks

If a socket or handle is closed abruptly (e.g. `socket.destroy()`), the
`'close'` event will be emitted in this phase. Otherwise it will be
emitted via `process.nextTick()`.

## `setImmediate()` vs `setTimeout()`

Expand Down