Skip to content

Commit b9448cc

Browse files
authored
guides: add guides from the core repo
This adds 4 guides from the nodejs/node repo to the guides section of the website. The documentation working group would like to make these guides more visible for end users. Ref: nodejs/node#10792
1 parent f9b6bcb commit b9448cc

File tree

4 files changed

+1276
-0
lines changed

4 files changed

+1276
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
title: Overview of Blocking vs Non-Blocking
3+
layout: docs.hbs
4+
---
5+
6+
# Overview of Blocking vs Non-Blocking
7+
8+
This overview covers the difference between **blocking** and **non-blocking**
9+
calls in Node.js. This overview will refer to the event loop and libuv but no
10+
prior knowledge of those topics is required. Readers are assumed to have a
11+
basic understanding of the JavaScript language and Node.js callback pattern.
12+
13+
> "I/O" refers primarily to interaction with the system's disk and
14+
> network supported by [libuv](http://libuv.org/).
15+
16+
17+
## Blocking
18+
19+
**Blocking** is when the execution of additional JavaScript in the Node.js
20+
process must wait until a non-JavaScript operation completes. This happens
21+
because the event loop is unable to continue running JavaScript while a
22+
**blocking** operation is occurring.
23+
24+
In Node.js, JavaScript that exhibits poor performance due to being CPU intensive
25+
rather than waiting on a non-JavaScript operation, such as I/O, isn't typically
26+
referred to as **blocking**. Synchronous methods in the Node.js standard library
27+
that use libuv are the most commonly used **blocking** operations. Native
28+
modules may also have **blocking** methods.
29+
30+
All of the I/O methods in the Node.js standard library provide asynchronous
31+
versions, which are **non-blocking**, and accept callback functions. Some
32+
methods also have **blocking** counterparts, which have names that end with
33+
`Sync`.
34+
35+
36+
## Comparing Code
37+
38+
**Blocking** methods execute **synchronously** and **non-blocking** methods
39+
execute **asynchronously**.
40+
41+
Using the File System module as an example, this is a **synchronous** file read:
42+
43+
```js
44+
const fs = require('fs');
45+
const data = fs.readFileSync('/file.md'); // blocks here until file is read
46+
```
47+
48+
And here is an equivalent **asynchronous** example:
49+
50+
```js
51+
const fs = require('fs');
52+
fs.readFile('/file.md', (err, data) => {
53+
if (err) throw err;
54+
});
55+
```
56+
57+
The first example appears simpler than the second but has the disadvantage of
58+
the second line **blocking** the execution of any additional JavaScript until
59+
the entire file is read. Note that in the synchronous version if an error is
60+
thrown it will need to be caught or the process will crash. In the asynchronous
61+
version, it is up to the author to decide whether an error should throw as
62+
shown.
63+
64+
Let's expand our example a little bit:
65+
66+
```js
67+
const fs = require('fs');
68+
const data = fs.readFileSync('/file.md'); // blocks here until file is read
69+
console.log(data);
70+
// moreWork(); will run after console.log
71+
```
72+
73+
And here is a similar, but not equivalent asynchronous example:
74+
75+
```js
76+
const fs = require('fs');
77+
fs.readFile('/file.md', (err, data) => {
78+
if (err) throw err;
79+
console.log(data);
80+
});
81+
// moreWork(); will run before console.log
82+
```
83+
84+
In the first example above, `console.log` will be called before `moreWork()`. In
85+
the second example `fs.readFile()` is **non-blocking** so JavaScript execution
86+
can continue and `moreWork()` will be called first. The ability to run
87+
`moreWork()` without waiting for the file read to complete is a key design
88+
choice that allows for higher throughput.
89+
90+
91+
## Concurrency and Throughput
92+
93+
JavaScript execution in Node.js is single threaded, so concurrency refers to the
94+
event loop's capacity to execute JavaScript callback functions after completing
95+
other work. Any code that is expected to run in a concurrent manner must allow
96+
the event loop to continue running as non-JavaScript operations, like I/O, are
97+
occurring.
98+
99+
As an example, let's consider a case where each request to a web server takes
100+
50ms to complete and 45ms of that 50ms is database I/O that can be done
101+
asynchronously. Choosing **non-blocking** asynchronous operations frees up that
102+
45ms per request to handle other requests. This is a significant difference in
103+
capacity just by choosing to use **non-blocking** methods instead of
104+
**blocking** methods.
105+
106+
The event loop is different than models in many other languages where additional
107+
threads may be created to handle concurrent work.
108+
109+
110+
## Dangers of Mixing Blocking and Non-Blocking Code
111+
112+
There are some patterns that should be avoided when dealing with I/O. Let's look
113+
at an example:
114+
115+
```js
116+
const fs = require('fs');
117+
fs.readFile('/file.md', (err, data) => {
118+
if (err) throw err;
119+
console.log(data);
120+
});
121+
fs.unlinkSync('/file.md');
122+
```
123+
124+
In the above example, `fs.unlinkSync()` is likely to be run before
125+
`fs.readFile()`, which would delete `file.md` before it is actually read. A
126+
better way to write this that is completely **non-blocking** and guaranteed to
127+
execute in the correct order is:
128+
129+
130+
```js
131+
const fs = require('fs');
132+
fs.readFile('/file.md', (err, data) => {
133+
if (err) throw err;
134+
console.log(data);
135+
fs.unlink('/file.md', (err) => {
136+
if (err) throw err;
137+
});
138+
});
139+
```
140+
141+
The above places a **non-blocking** call to `fs.unlink()` within the callback of
142+
`fs.readFile()` which guarantees the correct order of operations.
143+
144+
145+
## Additional Resources
146+
147+
- [libuv](http://libuv.org/)
148+
- [About Node.js](https://nodejs.org/en/about/)

0 commit comments

Comments
 (0)