Skip to content

Commit 5d28ce3

Browse files
jritFishrock123
authored andcommittedMar 22, 2016
doc: topic blocking vs non-blocking
The need for an overview of blocking vs non-blocking was identified in the docs WG Q1 roadmap. As there are several topics also pending creation, this one tries to hit the correct level of detail based on completion of the others. One which is referenced is https://github.com/nodejs/node/pull/4936/files and URLs within this PR need to change based on where that will land on the node website. PR-URL: #5326 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Stephen Belanger <[email protected]>
1 parent 21770c3 commit 5d28ce3

File tree

1 file changed

+143
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)
Please sign in to comment.