Home >Web Front-end >JS Tutorial >An explanation of blocking and non-blocking in Node.js

An explanation of blocking and non-blocking in Node.js

不言
不言forward
2018-11-15 17:30:551936browse

This article brings you an explanation of blocking and non-blocking in Node.js. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Blocking vs. Non-Blocking Overview

This overview covers the differences between blocking and non-blocking calls in Node.js. This overview will reference the event loop and libuv, No prior knowledge of these topics is required, but a basic understanding of the JavaScript language and Node.js callback patterns is assumed.

"I/O" mainly refers to the interaction with the disk and network of the system supported by libuv.

Blocking

Blocking means that the execution of other JavaScript in the Node.js process must wait until the non-JavaScript operation is completed. This happens because the event loop cannot continue to run JavaScript when the blocking operation occurs. .

In Node.js, JavaScript that exhibits poor performance due to being CPU intensive rather than waiting for non-JavaScript operations, such as I/O, is generally not called blocking. The synchronization method using libuv in the Node.js standard library is the most commonly used blocking operation, and native modules may also have blocking methods.

All I/O methods in the Node.js standard library provide non-blocking asynchronous versions and accept callback functions. Some methods also have corresponding blocking methods whose names start with Syncend.

Compare code

Blocking methods are executed synchronously, and non-blocking methods are executed asynchronously.

Taking the file system module as an example, this is a method to read files synchronously:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read

This is an equivalent asynchronous example:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});

First example Looks simpler than the second example, but the downside is that the second line prevents any other JavaScript from being executed until the entire file is read, note that in the synchronous version, if an error is thrown, you need to catch it, otherwise the process will crash , in the asynchronous version, it is up to the author whether an error should be thrown as shown.

Let’s expand our example a little bit:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
// moreWork(); will run after console.log

Here is a similar but not equivalent async example:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
// moreWork(); will run before console.log

In the first example above, we would console.log is called before moreWork(), in the second example, fs.readFile() is non-blocking, so JavaScript execution can continue, And moreWork() will be called first. The ability to run moreWork() without waiting for the file read to complete is a key design choice that can improve throughput.

Concurrency and Throughput

JavaScript execution in Node.js is single-threaded, so concurrency refers to the event loop's ability to execute JavaScript callback functions after completing other work, any expected Any code that runs concurrently must allow the event loop to continue running while non-JavaScript operations (such as I/O) are taking place.

As an example, let us consider a situation where each web server request takes 50ms to complete. 45ms of the 50ms is database I/O that can be completed asynchronously. Selecting non-blocking asynchronous operations can release each request 45 milliseconds to handle other requests, just by choosing to use a non-blocking method instead of a blocking method, which is a significant difference in capacity.

Event loops differ from the model in many other languages ​​where additional threads can be created to handle concurrent work.

The dangers of mixing blocking and non-blocking code

There are some patterns that should be avoided when dealing with I/O, let's look at an example:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
fs.unlinkSync('/file.md');

In the above example, fs .unlinkSync() will most likely be run before fs.readFile(), which will delete file.md before actually reading, a better way to write is completely non-blocking and guaranteed to be executed in the correct order:

const fs = require('fs');
fs.readFile('/file.md', (readFileErr, data) => {
  if (readFileErr) throw readFileErr;
  console.log(data);
  fs.unlink('/file.md', (unlinkErr) => {
    if (unlinkErr) throw unlinkErr;
  });
});

The above makes a non-blocking call to fs.unlink() in the callback of fs.readFile(), which ensures the correct order of operations.

The above is the detailed content of An explanation of blocking and non-blocking in Node.js. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:https://segmentfault.com/a/1190000017016894. If there is any infringement, please contact admin@php.cn delete