Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc: Adding guide on Timers #6825

Closed
wants to merge 18 commits into from
Closed
Changes from 4 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
154 changes: 154 additions & 0 deletions doc/guides/timers-in-node.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
title: Timers in node.js
layout: docs.hbs
---

# Timers in node.js and beyond
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually we capitalize "Node.js", or otherwise use just "node".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. thanks


Timers are a collection of global functions in node.js that allow you to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if we mention "Node.js" consistently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/node.js/Node.js

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep in mind you can actually do require('timers') to get at other stuff. They are just exposed the global object to mirror browsers. As such, I think there could be a better lead-in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworking this and fixing capitalization.

execute code after a set period of time. To fully understand when timer
functions will be executed, it's a good idea to read up on the the node
Copy link
Member

@jasnell jasnell May 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/node/Node.js (here and everywhere else it's mentioned ;-) )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty

[Event Loop](https://nodesource.com/blog/understanding-the-nodejs-event-loop/).
Copy link
Contributor

@Fishrock123 Fishrock123 Jun 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should link to https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md (using a local link), which is an updated and revised version of that blog post.


## Code Time Machine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems disconnected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to rework this a bit to provide a better introduction to the set functions.


The node API provides several ways to schedule your code to execute at
some point after the present moment.

### "When I say so" Execution ~ *setTimeout()*
Copy link
Contributor

@Fishrock123 Fishrock123 May 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*`setTimeout()`*


Using `setTimeout()`, you can schedule code to execute after a designated
amount of milliseconds. You may already be familiar with this function, as
it is a part of V8 and thus part of the browser JavaScript API.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am recalling correctly, setTimeout() is not implemented by V8. Node.js has it's own implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a part of V8

Is it really? ;)

I'm sure many people don't know (and that is ok! It means we have done a good job), but we actually need to have our own timers implementation. Browsers provide that, not the JS Engine. I'll add an extra note in the main comment thread here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! I'll fix this.


`setTimeout()` accepts the code to execute as its first argument and the
millisecond delay defined as a number literal as the second argument. Here
is an example of that:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in the docs, you can also pass any number of arguments though to the function being called via setTimeout(), beyond the 2nd argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added explanation and revised the example to demo this as well.


```js
function myFunc () {
console.log('funky');
}

setTimeout(myFunc, 1500);
```

The above function `myFunc()` will execute after approximately 1500
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just myFunc, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as close as possible to 1500 milliseconds later or similar, may be more accurate.

milliseconds (or 1.5 seconds) 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 executing code that
blocks or holds onto the event loop will push the execution of your timeout
back. You *can* guarantee that your timeout will not execute *sooner* than
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeout function will not execute?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meaning, it won't execute sooner than the timeout, it will execute on or after the timeout.

the declared timeout.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not actually always true on windows, but I think that was fixed now. Should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't know that! thanks!


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

`setImmediate()` allows you to execute code at the beginning of the next
event loop cycle. This code will execute *before* any timers or IO operations.
I like to think of this code execution as happening "right after this", meaning
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like personal opinion rather than the actual fact. Can you please reword this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally should avoid language such as "I like" or "allows you", etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... the "I like to think" line is a way of injecting a little personality into it, breaking down the order of when setImmediate() will run. I don't believe there's anything factually incorrect, but if you think it breaks the tone of the guide, then I can rework it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs can't contain lines like "I like to think", it should read as Node's docs and not someone's blog post about timers. Perhaps "A good mental model of setImmediate is..."

any code following the `setImmediate()` function call will execute before the
`setImmediate()` function argument. Here's an example:

```js
let order = 'before immediate\n';

setImmediate(() => {
order += 'executing immediate\n';
});

order += 'after immediate\n';

console.log(order);
```

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The executing immediate would not be emitted at all as it is not appended until after the console.log() is called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right. not sure how that snuck in. :-S

```

Note: `process.nextTick()` is very similar to `setImmediate()`. The two major
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. setImmediate() is what most people will think nextTick() does. (Indeed, what nextTick() used to do.)

The primary difference is that immediates allows IO to run before they are called, whereas nextTick does not. (nextTick is also not safe to call recursively in a potentially unbounded (infinite) way.)

differences are that `process.nextTick()` will run *before* any immediates that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

immediates is setImmediates, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, perhaps, is a bit too simplistic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, but I think there should be a prelude that explains that "timeouts" (Timeouts) are returned by setTimeout() and setInterval(), and "immediates" (Immediates) are returned by setImmediate()

are set. The second is that `process.nextTick()` is non-clearable, meaning once
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to put it something like (roughly) nextTick is just like calling the function itself, as you can't cancel a function call. Only, it is not called within the original call stack, so it is asynchronous.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to rework this whole paragraph to better illustrate the differences with process.nextTick().

you've scheduled code to execute with `process.nextTick()` you cannot stop that
code, unlike with `setImmediate()`.

### "Deja vu" Execution ~ *setInterval()*

If there is a block of code that you want to execute multiple times, you can
use `setInterval()` to execute that code. `setInterval()` takes a function
argument that will run and infinite number of times with a given millisecond
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and is not needed here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty

delay. Just 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 every 1500 milliseconds, or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

about every

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it

1.5 seconds, until it is stopped (see below).

## Master of the Timerverse

What would a Code Time Machine be without the ability to turn it off?
`setTimeout()`, `setImmediate()`, and `setInterval()` return a timer object
that can be used to reference the set timeout, immediate, or interval object.
By passing said objective into the respective `clear` function, execution of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

said object

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

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);
```

## Last Train to Nowhere

The node Timer API provides two functions intended to augment timer behavior
with `unref()` and `ref()`. If you have a timer object scheduled using a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should specify that these are on Timeouts prototype. Also need to state above that intervals also give you a Timeout class, but immediates give you an Immediate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good distinction, I'll add this in.

`set` function, you can call `unref()` on that object. This will change
the behavior slightly, and not call the timer object *if it is the last
code to execute*. Instead, it will let the program exit cleanly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better stated as it will not keep the process alive waiting to execute

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty


In similar fashion, a timer object that has had `unref()` called on it
can remove that behavior by calling `ref()` on that same timer object,
which will then ensure its execution. See below for examples of both:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

however this does not *exactly* restore the initial behavior for performance reasons


```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();
});
```