Skip to content

Commit 0e52861

Browse files
ryanmurakamiMylesBorins
authored andcommitted
doc: grammar fixes to event loop guide
PR-URL: #7479 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 77df523 commit 0e52861

File tree

1 file changed

+90
-82
lines changed

1 file changed

+90
-82
lines changed

doc/topics/the-event-loop-timers-and-nexttick.md

+90-82
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ offloading operations to the system kernel whenever possible.
99
Since most modern kernels are multi-threaded, they can handle multiple
1010
operations executing in the background. When one of these operations
1111
completes, the kernel tells Node.js so that the appropriate callback
12-
may added to the `poll` queue to eventually be executed. We'll explain
12+
may added to the **poll** queue to eventually be executed. We'll explain
1313
this in further detail later in this topic.
1414

1515
## Event Loop Explained
1616

1717
When Node.js starts, it initializes the event loop, processes the
1818
provided input script (or drops into the REPL, which is not covered in
1919
this document) which may make async API calls, schedule timers, or call
20-
`process.nextTick()`, then begins processing the event loop.
20+
`process.nextTick()`, then begins processing the event loop.
2121

2222
The following diagram shows a simplified overview of the event loop's
2323
order of operations.
@@ -47,36 +47,36 @@ Each phase has a FIFO queue of callbacks to execute. While each phase is
4747
special in its own way, generally, when the event loop enters a given
4848
phase, it will perform any operations specific to that phase, then
4949
execute callbacks in that phase's queue until the queue has been
50-
exhausted or the maximum number of callbacks have executed. When the
50+
exhausted or the maximum number of callbacks has executed. When the
5151
queue has been exhausted or the callback limit is reached, the event
5252
loop will move to the next phase, and so on.
5353

5454
Since any of these operations may schedule _more_ operations and new
55-
events processed in the `poll` phase are queued by the kernel, poll
55+
events processed in the **poll** phase are queued by the kernel, poll
5656
events can be queued while polling events are being processed. As a
5757
result, long running callbacks can allow the poll phase to run much
58-
longer than a timer's threshold. See the [`timers`](#timers) and
59-
[`poll`](#poll) sections for more details.
58+
longer than a timer's threshold. See the [**timers**](#timers) and
59+
[**poll**](#poll) sections for more details.
6060

6161
_**NOTE:** There is a slight discrepancy between the Windows and the
6262
Unix/Linux implementation, but that's not important for this
6363
demonstration. The most important parts are here. There are actually
6464
seven or eight steps, but the ones we care about — ones that Node.js
65-
actually uses are those above._
65+
actually uses - are those above._
6666

6767

68-
## Phases Overview:
68+
## Phases Overview
6969

70-
* `timers`: this phase executes callbacks scheduled by `setTimeout()`
70+
* **timers**: this phase executes callbacks scheduled by `setTimeout()`
7171
and `setInterval()`.
72-
* `I/O callbacks`: most types of callback except timers, setImmedate, close
73-
* `idle, prepare`: only used internally
74-
* `poll`: retrieve new I/O events; node will block here when appropriate
75-
* `check`: setImmediate callbacks are invoked here
76-
* `close callbacks`: e.g socket.on('close', ...)
72+
* **I/O callbacks**: most types of callback except timers, `setImmedate()`, close
73+
* **idle, prepare**: only used internally
74+
* **poll**: retrieve new I/O events; node will block here when appropriate
75+
* **check**: `setImmediate()` callbacks are invoked here
76+
* **close callbacks**: e.g socket.on('close', ...)
7777

7878
Between each run of the event loop, Node.js checks if it is waiting for
79-
any asynchronous I/O or timer and it shuts down cleanly if there are not
79+
any asynchronous I/O or timers and shuts down cleanly if there are not
8080
any.
8181

8282
## Phases in Detail
@@ -90,7 +90,7 @@ scheduled after the specified amount of time has passed; however,
9090
Operating System scheduling or the running of other callbacks may delay
9191
them.
9292

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

9696
For example, say you schedule a timeout to execute after a 100 ms
@@ -102,10 +102,8 @@ takes 95 ms:
102102
var fs = require('fs');
103103

104104
function someAsyncOperation (callback) {
105-
106-
// let's assume this takes 95ms to complete
105+
// Assume this takes 95ms to complete
107106
fs.readFile('/path/to/file', callback);
108-
109107
}
110108

111109
var timeoutScheduled = Date.now();
@@ -131,78 +129,77 @@ someAsyncOperation(function () {
131129
});
132130
```
133131

134-
When the event loop enters the `poll` phase, it has an empty queue
135-
(`fs.readFile()` has not completed) so it will wait for the number of ms
132+
When the event loop enters the **poll** phase, it has an empty queue
133+
(`fs.readFile()` has not completed), so it will wait for the number of ms
136134
remaining until the soonest timer's threshold is reached. While it is
137135
waiting 95 ms pass, `fs.readFile()` finishes reading the file and its
138-
callback which takes 10 ms to complete is added to the `poll` queue and
136+
callback which takes 10 ms to complete is added to the **poll** queue and
139137
executed. When the callback finishes, there are no more callbacks in the
140138
queue, so the event loop will see that the threshold of the soonest
141-
timer has been reached then wrap back to the `timers` phase to execute
139+
timer has been reached then wrap back to the **timers** phase to execute
142140
the timer's callback. In this example, you will see that the total delay
143-
between the timer being scheduled and its callback being executed will
141+
between the timer being scheduled and its callback being executed will
144142
be 105ms.
145143

146-
Note: To prevent the `poll` phase from starving the event loop, libuv
147-
also has a hard maximum (system dependent) before it stops `poll`ing for
144+
Note: To prevent the **poll** phase from starving the event loop, libuv
145+
also has a hard maximum (system dependent) before it stops polling for
148146
more events.
149147

150-
### I/O callbacks:
148+
### I/O callbacks
151149

152150
This phase executes callbacks for some system operations such as types
153151
of TCP errors. For example if a TCP socket receives `ECONNREFUSED` when
154152
attempting to connect, some \*nix systems want to wait to report the
155-
error. This will be queued to execute in the `I/O callbacks` phase.
156-
157-
### poll:
153+
error. This will be queued to execute in the **I/O callbacks** phase.
158154

159-
The poll phase has two main functions:
155+
### poll
160156

161-
1. Executing scripts for timers who's threshold has elapsed, then
162-
2. Processing events in the `poll` queue.
157+
The **poll** phase has two main functions:
163158

159+
1. Executing scripts for timers whose threshold has elapsed, then
160+
2. Processing events in the **poll** queue.
164161

165-
When the event loop enters the `poll` phase _and there are no timers
162+
When the event loop enters the **poll** phase _and there are no timers
166163
scheduled_, one of two things will happen:
167164

168-
* _If the `poll` queue **is not empty**_, the event loop will iterate
169-
through its queue of callbacks executing them synchronously until
170-
either the queue has been exhausted, or the system-dependent hard limit
165+
* _If the **poll** queue **is not empty**_, the event loop will iterate
166+
through its queue of callbacks executing them synchronously until
167+
either the queue has been exhausted, or the system-dependent hard limit
171168
is reached.
172169

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

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

183-
Once the `poll` queue is empty the event loop will check for timers
180+
Once the **poll** queue is empty the event loop will check for timers
184181
_whose time thresholds have been reached_. If one or more timers are
185-
ready, the event loop will wrap back to the timers phase to execute
182+
ready, the event loop will wrap back to the **timers** phase to execute
186183
those timers' callbacks.
187184

188-
### `check`:
185+
### check
189186

190-
This phase allows a person to execute callbacks immediately after the
191-
`poll` phase has completed. If the `poll` phase becomes idle and
192-
scripts have been queued with `setImmediate()`, the event loop may
193-
continue to the `check` phase rather than waiting.
187+
This phase allows a person to execute callbacks immediately after the
188+
**poll** phase has completed. If the **poll** phase becomes idle and
189+
scripts have been queued with `setImmediate()`, the event loop may
190+
continue to the **check** phase rather than waiting.
194191

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

199196
Generally, as the code is executed, the event loop will eventually hit
200-
the `poll` phase where it will wait for an incoming connection, request,
201-
etc. However, after a callback has been scheduled with `setImmediate()`,
202-
then the `poll` phase becomes idle, it will end and continue to the
203-
`check` phase rather than waiting for `poll` events.
197+
the **poll** phase where it will wait for an incoming connection, request,
198+
etc. However, if a callback has been scheduled with `setImmediate()`
199+
and the **poll** phase becomes idle, it will end and continue to the
200+
**check** phase rather than waiting for **poll** events.
204201

205-
### `close callbacks`:
202+
### close callbacks
206203

207204
If a socket or handle is closed abruptly (e.g. `socket.destroy()`), the
208205
`'close'` event will be emitted in this phase. Otherwise it will be
@@ -214,12 +211,12 @@ emitted via `process.nextTick()`.
214211
ways depending on when they are called.
215212

216213
* `setImmediate()` is designed to execute a script once the current
217-
`poll` phase completes.
218-
* `setTimeout()` schedules a script to be run
219-
after a minimum threshold in ms has elapsed.
214+
**poll** phase completes.
215+
* `setTimeout()` schedules a script to be run after a minimum threshold
216+
in ms has elapsed.
220217

221218
The order in which the timers are executed will vary depending on the
222-
context in which they are called. If both are called from within the
219+
context in which they are called. If both are called from within the
223220
main module, then timing will be bound by the performance of the process
224221
(which can be impacted by other applications running on the machine).
225222

@@ -248,7 +245,6 @@ setImmediate(function immediate () {
248245
immediate
249246
timeout
250247

251-
252248
However, if you move the two calls within an I/O cycle, the immediate
253249
callback is always executed first:
254250

@@ -278,22 +274,22 @@ The main advantage to using `setImmediate()` over `setTimeout()` is
278274
`setImmediate()` will always be executed before any timers if scheduled
279275
within an I/O cycle, independently of how many timers are present.
280276

281-
## `process.nextTick()`:
277+
## `process.nextTick()`
282278

283279
### Understanding `process.nextTick()`
284280

285281
You may have noticed that `process.nextTick()` was not displayed in the
286-
diagram, even though its a part of the asynchronous API. This is because
282+
diagram, even though it's a part of the asynchronous API. This is because
287283
`process.nextTick()` is not technically part of the event loop. Instead,
288-
the nextTickQueue will be processed after the current operation
289-
completes, regardless of the current `phase` of the event loop.
284+
the `nextTickQueue` will be processed after the current operation
285+
completes, regardless of the current phase of the event loop.
290286

291287
Looking back at our diagram, any time you call `process.nextTick()` in a
292288
given phase, all callbacks passed to `process.nextTick()` will be
293289
resolved before the event loop continues. This can create some bad
294290
situations because **it allows you to "starve" your I/O by making
295-
recursive `process.nextTick()` calls.** which prevents the event loop
296-
from reaching the `poll` phase.
291+
recursive `process.nextTick()` calls**, which prevents the event loop
292+
from reaching the **poll** phase.
297293

298294
### Why would that be allowed?
299295

@@ -319,9 +315,9 @@ What we're doing is passing an error back to the user but only *after*
319315
we have allowed the rest of the user's code to execute. By using
320316
`process.nextTick()` we guarantee that `apiCall()` always runs its
321317
callback *after* the rest of the user's code and *before* the event loop
322-
is allowed to proceed. To acheive this, the JS call stack is allowed to
318+
is allowed to proceed. To achieve this, the JS call stack is allowed to
323319
unwind then immediately execute the provided callback which allows a
324-
person to make recursive calls to nextTick without reaching a
320+
person to make recursive calls to `process.nextTick()` without reaching a
325321
`RangeError: Maximum call stack size exceeded from v8`.
326322

327323
This philosophy can lead to some potentially problematic situations.
@@ -343,21 +339,33 @@ var bar = 1;
343339
```
344340

345341
The user defines `someAsyncApiCall()` to have an asynchronous signature,
346-
actually operates synchronously. When it is called, the callback
347-
provided to `someAsyncApiCall ()` is called in the same phase of the
342+
but it actually operates synchronously. When it is called, the callback
343+
provided to `someAsyncApiCall()` is called in the same phase of the
348344
event loop because `someAsyncApiCall()` doesn't actually do anything
349-
asynchronously. As a result, the callback tries to reference `bar` but
350-
it may not have that variable in scope yet because the script has not
345+
asynchronously. As a result, the callback tries to reference `bar` even
346+
though it may not have that variable in scope yet, because the script has not
351347
been able to run to completion.
352348

353-
By placing it in a `process.nextTick()`, the script still has the
349+
By placing the callback in a `process.nextTick()`, the script still has the
354350
ability to run to completion, allowing all the variables, functions,
355-
etc., to be initialized prior to the callback being called. It also has
351+
etc., to be initialized prior to the callback being called. It also has
356352
the advantage of not allowing the event loop to continue. It may be
357-
useful that the user be alerted to an error before the event loop is
358-
allowed to continue.
353+
useful for the user to be alerted to an error before the event loop is
354+
allowed to continue. Here is the previous example using `process.nextTick()`:
355+
356+
```js
357+
function someAsyncApiCall (callback) {
358+
process.nextTick(callback);
359+
};
360+
361+
someAsyncApiCall(() => {
362+
console.log('bar', bar); // 1
363+
});
364+
365+
var bar = 1;
366+
```
359367

360-
A real world example in node would be:
368+
Here's another real world example:
361369

362370
```js
363371
const server = net.createServer(() => {}).listen(8080);
@@ -367,10 +375,10 @@ server.on('listening', () => {});
367375

368376
When only a port is passed the port is bound immediately. So the
369377
`'listening'` callback could be called immediately. Problem is that the
370-
`.on('listening')` will not have been set by that time.
378+
`.on('listening')` will not have been set by that time.
371379

372380
To get around this the `'listening'` event is queued in a `nextTick()`
373-
to allow the script to run to completion. Which allows the user to set
381+
to allow the script to run to completion. Which allows the user to set
374382
any event handlers they want.
375383

376384
## `process.nextTick()` vs `setImmediate()`
@@ -389,7 +397,7 @@ percentage of the packages on npm. Every day more new modules are being
389397
added, which mean every day we wait, more potential breakages occur.
390398
While they are confusing, the names themselves won't change.
391399

392-
*We recommend developers use `setImmediate()` in all cases because its
400+
*We recommend developers use `setImmediate()` in all cases because it's
393401
easier to reason about (and it leads to code that's compatible with a
394402
wider variety of environments, like browser JS.)*
395403

@@ -413,11 +421,11 @@ server.listen(8080);
413421
server.on('listening', function() { });
414422
```
415423

416-
Say that listen() is run at the beginning of the event loop, but the
424+
Say that `listen()` is run at the beginning of the event loop, but the
417425
listening callback is placed in a `setImmediate()`. Now, unless a
418-
hostname is passed binding to the port will happen immediately. Now for
419-
the event loop to proceed it must hit the `poll` phase, which means
420-
there is a non-zero chance that a connection could have been received
426+
hostname is passed binding to the port will happen immediately. Now for
427+
the event loop to proceed it must hit the **poll** phase, which means
428+
there is a non-zero chance that a connection could have been received
421429
allowing the connection event to be fired before the listening event.
422430

423431
Another example is running a function constructor that was to, say,

0 commit comments

Comments
 (0)