Skip to content

Commit

Permalink
doc: add guide for Node.js Timers
Browse files Browse the repository at this point in the history
Refs: nodejs/docs#76
PR-URL: #6825
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Sakthipriyan Vairamani <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
  • Loading branch information
ryanmurakami authored and Fishrock123 committed Jul 5, 2016
1 parent b383fdd commit 45f83e5
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 22 deletions.
192 changes: 192 additions & 0 deletions doc/guides/timers-in-node.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
---
title: Timers in Node.js
layout: docs.hbs
---

# Timers in Node.js and beyond

The Timers module in Node.js contains functions that execute code after a set
period of time. Timers do not need to be imported via `require()`, since
all the methods are available globally to emulate the browser JavaScript API.
To fully understand when timer functions will be executed, it's a good idea to
read up on the the Node.js
[Event Loop](../topics/the-event-loop-timers-and-nexttick).

## Controlling the Time Continuum with Node.js

The Node.js API provides several ways of scheduling code to execute at
some point after the present moment. The functions below may seem familiar,
since they are available in most browsers, but Node.js actually provides
its own implementation of these methods. Timers integrate very closely
with the system, and despite the fact that the API mirrors the browser
API, there are some differences in implementation.

### "When I say so" Execution ~ *`setTimeout()`*

`setTimeout()` can be used to schedule code execution after a designated
amount of milliseconds. This function is similar to
[`window.setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout)
from the browser JavaScript API, however a string of code cannot be passed
to be executed.

`setTimeout()` accepts a function to execute as its first argument and the
millisecond delay defined as a number as the second argument. Additional
arguments may also be included and these will be passed on to the function. Here
is an example of that:

```js
function myFunc (arg) {
console.log('arg was => ' + arg);
}

setTimeout(myFunc, 1500, 'funky');
```

The above function `myFunc()` will execute as close to 1500
milliseconds (or 1.5 seconds) as possible due to the call of `setTimeout()`.

The timeout interval that is set cannot be relied upon to execute after
that *exact* number of milliseconds. This is because other executing code that
blocks or holds onto the event loop will push the execution of the timeout
back. The *only* guarantee is that the timeout will not execute *sooner* than
the declared timeout interval.

`setTimeout()` returns a `Timeout` object that can be used to reference the
timeout that was set. This returned object can be used to cancel the timeout (
see `clearTimeout()` below) as well as change the execution behavior (see
`unref()` below).

### "Right after this" Execution ~ *`setImmediate()`*

`setImmediate()` will execute code at the end of the current event loop cycle.
This code will execute *after* any I/O operations in the current event loop and
*before* any timers scheduled for the next event loop. This code execution
could be thought of as happening "right after this", meaning any code following
the `setImmediate()` function call will execute before the `setImmediate()`
function argument.

The first argument to `setImmediate()` will be the function to execute. Any
subsequent arguments will be passed to the function when it is executed.
Here's an example:

```js
console.log('before immediate');

setImmediate((arg) => {
console.log(`executing immediate: ${arg}`);
}, 'so immediate');

console.log('after immediate');
```

The above function passed to `setImmediate()` will execute after all runnable
code has executed, and the console output will be:

```shell
before immediate
after immediate
executing immediate: so immediate
```

`setImmediate()` returns and `Immediate` object, which can be used to cancel
the scheduled immediate (see `clearImmediate()` below).

Note: Don't get `setImmediate()` confused with `process.nextTick()`. There are
some major ways they differ. The first is that `process.nextTick()` will run
*before* any `Immediate`s that are set as well as before any scheduled I/O.
The second is that `process.nextTick()` is non-clearable, meaning once
code has been scheduled to execute with `process.nextTick()`, the execution
cannot be stopped, just like with a normal function. Refer to [this guide](../topics/the-event-loop-timers-and-nexttick#processnexttick)
to better understand the operation of `process.nextTick()`.

### "Infinite Loop" Execution ~ *`setInterval()`*

If there is a block of code that should execute multiple times, `setInterval()`
can be used to execute that code. `setInterval()` takes a function
argument that will run an infinite number of times with a given millisecond
delay as the second argument. Just like `setTimeout()`, additional arguments
can be added beyond the delay, and these will be passed on to the function call.
Also like `setTimeout()`, the delay cannot be guaranteed because of operations
that may hold on to the event loop, and therefore should be treated as an
approximate delay. See the below example:

```js
function intervalFunc () {
console.log('Cant stop me now!');
}

setInterval(intervalFunc, 1500);
```
In the above example, `intervalFunc()` will execute about every 1500
milliseconds, or 1.5 seconds, until it is stopped (see below).

Just like `setTimeout()`, `setInterval()` also returns a `Timeout` object which
can be used to reference and modify the interval that was set.

## Clearing the Future

What can be done if a `Timeout` or `Immediate` object needs to be cancelled?
`setTimeout()`, `setImmediate()`, and `setInterval()` return a timer object
that can be used to reference the set `Timeout` or `Immediate` object.
By passing said object into the respective `clear` function, execution of
that object will be halted completely. The respective functions are
`clearTimeout()`, `clearImmediate()`, and `clearInterval()`. See the example
below for an example of each:

```js
let timeoutObj = setTimeout(() => {
console.log('timeout beyond time');
}, 1500);

let immediateObj = setImmediate(() => {
console.log('immediately executing immediate');
});

let intervalObj = setInterval(() => {
console.log('interviewing the interval');
}, 500);

clearTimeout(timeoutObj);
clearImmediate(immediateObj);
clearInterval(intervalObj);
```

## Leaving Timeouts Behind

Remember that `Timeout` objects are returned by `setTimeout` and `setInterval`.
The `Timeout` object provides two functions intended to augment `Timeout`
behavior with `unref()` and `ref()`. If there is a `Timeout` object scheduled
using a `set` function, `unref()` can be called on that object. This will change
the behavior slightly, and not call the `Timeout` object *if it is the last
code to execute*. The `Timeout` object will not keep the process alive, waiting
to execute.

In similar fashion, a `Timeout` object that has had `unref()` called on it
can remove that behavior by calling `ref()` on that same `Timeout` object,
which will then ensure its execution. Be aware, however, that this does
not *exactly* restore the initial behavior for performance reasons. See
below for examples of both:

```js
let timerObj = setTimeout(() => {
console.log('will i run?');
});

// if left alone, this statement will keep the above
// timeout from running, since the timeout will be the only
// thing keeping the program from exiting
timerObj.unref();

// we can bring it back to life by calling ref() inside
// an immediate
setImmediate(() => {
timerObj.ref();
});
```
## Further Down the Event Loop

There's much more to the Event Loop and Timers than this guide
has covered. To learn more about the internals of the Node.js
Event Loop and how Timers operate during execution, check out
this Node.js guide: [The Node.js Event Loop, Timers, and
process.nextTick()](../topics/the-event-loop-timers-and-nexttick).
44 changes: 22 additions & 22 deletions doc/topics/the-event-loop-timers-and-nexttick.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

The event loop is what allows Node.js to perform non-blocking I/O
operations — despite the fact that JavaScript is single-threaded — by
offloading operations to the system kernel whenever possible.
offloading operations to the system kernel whenever possible.

Since most modern kernels are multi-threaded, they can handle multiple
operations executing in the background. When one of these operations
completes, the kernel tells Node.js so that the appropriate callback
may added to the `poll` queue to eventually be executed. We'll explain
this in further detail later in this topic.

## Event Loop Explained
## Event Loop Explained

When Node.js starts, it initializes the event loop, processes the
provided input script (or drops into the REPL, which is not covered in
Expand Down Expand Up @@ -67,7 +67,7 @@ actually uses are those above._

## Phases Overview:

* `timers`: this phase executes callbacks scheduled by `setTimeout()`
* `timers`: this phase executes callbacks scheduled by `setTimeout()`
and `setInterval()`.
* `I/O callbacks`: most types of callback except timers, setImmedate, close
* `idle, prepare`: only used internally
Expand All @@ -88,22 +88,22 @@ _may be executed_ rather than the **exact** time a person _wants it to
be executed_. Timers callbacks will run as early as they can be
scheduled after the specified amount of time has passed; however,
Operating System scheduling or the running of other callbacks may delay
them.
them.

_**Note**: Technically, the [`poll` phase](#poll) controls when timers
_**Note**: Technically, the [`poll` phase](#poll) controls when timers
are executed._

For example, say you schedule a timeout to execute after a 100 ms
threshold, then your script starts asynchronously reading a file which
For example, say you schedule a timeout to execute after a 100 ms
threshold, then your script starts asynchronously reading a file which
takes 95 ms:

```js

var fs = require('fs');

function someAsyncOperation (callback) {
// let's assume this takes 95ms to complete

// let's assume this takes 95ms to complete
fs.readFile('/path/to/file', callback);

}
Expand Down Expand Up @@ -149,12 +149,12 @@ more events.

### I/O callbacks:

This phase executes callbacks for some system operations such as types
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 `I/O callbacks` phase.

### poll:
### poll:

The poll phase has two main functions:

Expand All @@ -171,7 +171,7 @@ 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:
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.
Expand Down Expand Up @@ -202,7 +202,7 @@ etc. However, after a callback has been scheduled with `setImmediate()`,
then the `poll` phase becomes idle, it will end and continue to the
`check` phase rather than waiting for `poll` events.

### `close callbacks`:
### `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
Expand All @@ -211,10 +211,10 @@ emitted via `process.nextTick()`.
## `setImmediate()` vs `setTimeout()`

`setImmediate` and `setTimeout()` are similar, but behave in different
ways depending on when they are called.
ways depending on when they are called.

* `setImmediate()` is designed to execute a script once the current
`poll` phase completes.
`poll` phase completes.
* `setTimeout()` schedules a script to be run
after a minimum threshold in ms has elapsed.

Expand Down Expand Up @@ -379,7 +379,7 @@ We have two calls that are similar as far as users are concerned, but
their names are confusing.

* `process.nextTick()` fires immediately on the same phase
* `setImmediate()` fires on the following iteration or 'tick' of the
* `setImmediate()` fires on the following iteration or 'tick' of the
event loop

In essence, the names should be swapped. `process.nextTick()` fires more
Expand All @@ -393,7 +393,7 @@ While they are confusing, the names themselves won't change.
easier to reason about (and it leads to code that's compatible with a
wider variety of environments, like browser JS.)*

## Why use `process.nextTick()`?
## Why use `process.nextTick()`?

There are two main reasons:

Expand All @@ -420,7 +420,7 @@ the event loop to proceed it must hit the `poll` phase, which means
there is a non-zero chance that a connection could have been received
allowing the connection event to be fired before the listening event.

Another example is running a function constructor that was to, say,
Another example is running a function constructor that was to, say,
inherit from `EventEmitter` and it wanted to call an event within the
constructor:

Expand All @@ -440,10 +440,10 @@ myEmitter.on('event', function() {
});
```

You can't emit an event from the constructor immediately
because the script will not have processed to the point where the user
assigns a callback to that event. So, within the constructor itself,
you can use `process.nextTick()` to set a callback to emit the event
You can't emit an event from the constructor immediately
because the script will not have processed to the point where the user
assigns a callback to that event. So, within the constructor itself,
you can use `process.nextTick()` to set a callback to emit the event
after the constructor has finished, which provides the expected results:

```js
Expand Down

0 comments on commit 45f83e5

Please sign in to comment.