Introduction to the
Because javascript is single-threaded by default, this means that code cannot create new threads to execute in parallel. But for javascript that initially ran in a browser, a single-threaded synchronous execution environment was obviously not enough to respond to user clicks and mouse movements. The browser implements a set of apis that allow javascript to asynchronously respond to a page’s request events with callbacks.
Further, NodeJS introduces non-blocking I/O, extending the concept of asyncrony to file access, network calls, and more.
Today, we’ll take a closer look at the pros, cons and trends of asynchronous programming.
Synchronous asynchronous and blocking non-blocking
Before discussing asynchronous programming for NodeJS, let’s discuss the confusing concepts of synchronous, asynchronous, blocking, and non-blocking.
The so-called blocking and non-blocking refers to whether the process or thread needs to wait for operations or data reading and writing and whether other operations can be performed during the waiting process.
If a wait is required and the thread or process can do nothing but wait stupidly, the operation is said to be blocked.
Conversely, if a process or thread can do something else while performing an operation or reading or writing data, the operation is said to be non-blocking.
Synchronous and asynchronous refers to ways of accessing data, and synchronous refers to the need to actively read data, which may be blocked or non-blocking. Asynchronous means that you don’t have to actively read the data, it’s passive notification.
Obviously, a callback in javascript is a passive notification, which we can call an asynchronous call.
Callbacks in javascript
Callbacks in javascript are a very good example of asynchronous programming:
document.getElementById('button').addEventListener('click'.() = > {
console.log('button clicked! ');
})
Copy the code
In the code above, we add a click event listener to the button. If the click event is heard, the callback function will output the corresponding message.
The callback function is a normal function, but it is passed as an argument to the addEventListener and is called only when an event is raised.
The setTimeout and setInterval we talked about in the last article are actually asynchronous callback functions.
Error handling of callback functions
How do you handle callback error messages in NodeJS? Nodejs takes a very clever approach. In NodeJS, the first argument in any callback function is an error object, and we can determine whether the error object exists or not to handle the error accordingly.
fs.readFile('/ file. Json'.(err, data) = > {
if(err ! = =null) {
// Processing error
console.log(err)
return
}
// If there is no error, process the data.
console.log(data)
})
Copy the code
The callback hell
Javascript’s callback, while excellent, effectively solves the synchronization problem. Unfortunately, this is callback hell if we need to rely on the return value of the callback function for the next operation.
Calling callback hell is a bit of an exaggeration, but it reflects the problem with callback functions in one way.
fs.readFile('/a.json'.(err, data) = > {
if(err ! = =null) {
fs.readFile('/b.json'.(err,data) = >{
//callback inside callback})}})Copy the code
How do you solve it?
Don’t worry about ES6 introducing Promises and ES2017 introducing Async/Await.
The Promise in ES6
What is a Promise
Promise is a solution to asynchronous programming that is more reasonable and powerful than the traditional “callback functions and events” solution.
A Promise is simply a container that holds the result of an event (usually an asynchronous operation) that will end in the future.
Syntactically, a Promise is an object from which to get messages for asynchronous operations.
The characteristics of the Promise
Promise has two features:
- The status of an object is not affected.
The Promise object represents an asynchronous operation and has three states: Pending, Resolved, and Rejected.
Only the result of an asynchronous operation can determine the current state, and no other operation can change the state.
- Once the state changes, it never changes again, and you can get this result at any time.
There are only two possibilities for a Promise object to change state: from Pending to Resolved and from Pending to Rejected.
This is quite different from an Event, which has the characteristic that if you miss it and listen again, you will not get the result.
The advantages of the Promise
Promise expresses asynchronous operations as a flow of synchronous operations, avoiding layers of nested callback functions.
Promise objects provide a unified interface that makes it easier to control asynchronous operations.
The shortcoming of Promise
-
There is no way to cancel a Promise, which is executed as soon as it is created and cannot be cancelled halfway through.
-
If the callback function is not set, errors thrown inside a Promise are not reflected outside.
-
When you are in a Pending state, you have no way of knowing what stage of progress you are currently in (just started or about to complete).
The use of the Promise
The Promise object is a constructor that generates a Promise instance:
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* Asynchronous operation succeeded */){
resolve(value);
} else{ reject(error); }});Copy the code
A promise can be followed by a then operation, which can be followed by two function arguments. The first function argument is the value of resolve when constructing a promise, and the second function argument is the error of reject when constructing a promise.
promise.then(function(value) {
// success
}, function(error) {
// failure }
);
Copy the code
Let’s look at a concrete example:
function timeout(ms){
return new Promise(((resolve, reject) = > {
setTimeout(resolve,ms,'done');
}))
}
timeout(100).then(value= > console.log(value));
Copy the code
A setTimeout method is called in the Promise, and the resolve method is periodically triggered, passing in the argument done.
Finally, the program prints done.
The order in which promises are executed
Promises are implemented as soon as they are created. Methods in promise.then, however, are called again after a call cycle, as in the following example:
let promise = new Promise(((resolve, reject) = > {
console.log('Step1');
resolve();
}));
promise.then(() = > {
console.log('Step3');
});
console.log('Step2'); Output: Step1 Step2 Step3Copy the code
Async and await
Promise was fine, of course, and we converted the callback hell into a chain call. We use then to concatenate multiple promises, and the result of the previous Promise resolve is the argument to then in the next Promise.
What are the disadvantages of chain calls?
For example, if we resolve a value from a promise, we need to perform some business logic processing based on that value.
If the business logic is long, we need to write long business logic code in the next THEN. This makes our code look very redundant.
Is there a way to directly return the result of resolve in a promise?
The answer is await.
When an await is preceded by a promise, the calling code stops until the promise is resolved or rejected.
Note that await must be placed in async functions. Let’s look at an example of async and await:
const logAsync = () = > {
return new Promise(resolve= > {
setTimeout(() = > resolve('Little Pony'), 5000)})}Copy the code
Above we define a logAsync function that returns a Promise, which can be considered asynchronous because the Promise internally uses setTimeout to resolve.
To get resolve using await, we need to put it in an async function:
const doSomething = async() = > {const resolveValue = await logAsync();
console.log(resolveValue);
}
Copy the code
The execution order of async
Await is actually waiting for the resolve result of a promise. Let’s combine the above examples:
const logAsync = () = > {
return new Promise(resolve= > {
setTimeout(() = > resolve('Little Pony'), 1000)})}const doSomething = async() = > {const resolveValue = await logAsync();
console.log(resolveValue);
}
console.log('before')
doSomething();
console.log('after')
Copy the code
The above example output:
Before after Little MarcoCopy the code
As you can see, AYSNC is executed asynchronously, and its order is after the current cycle.
The characteristics of the async
Async makes all subsequent functions become promises, even if subsequent functions do not explicitly return promises.
const asyncReturn = async() = > {return 'async return'
}
asyncReturn().then(console.log)
Copy the code
Since only a Promise can be followed by then, we can see that async encapsulates an ordinary function as a Promise:
const asyncReturn = async() = > {return Promise.resolve('async return')
}
asyncReturn().then(console.log)
Copy the code
conclusion
Promise avoids callback hell by rewriting callback inside callback to the chain-call form of then.
But chained calls are not easy to read and debug. So async and await.
Async and await change chained calls to programmatically sequential execution syntax, making them easier to understand and debug.
Here’s a comparison. Let’s look at using Promise:
const getUserInfo = () = > {
return fetch('/users.json') // Get the user list
.then(response= > response.json()) / / parsing JSON
.then(users= > users[0]) // Select the first user
.then(user= > fetch(`/users/${user.name}`)) // Get user data
.then(userResponse= > userResponse.json()) / / parsing JSON
}
getUserInfo()
Copy the code
Rewrite it to async and await:
const getUserInfo = async() = > {const response = await fetch('/users.json') // Get the user list
const users = await response.json() / / parsing JSON
const user = users[0] // Select the first user
const userResponse = await fetch(`/users/${user.name}`) // Get user data
const userData = await userResponse.json() / / parsing JSON
return userData
}
getUserInfo()
Copy the code
You can see that the business logic becomes clearer. At the same time, we get a lot of intermediate values, which makes it easy to debug.
Author: Flydean program stuff
Link to this article: www.flydean.com/nodejs-asyn…
Source: Flydean’s blog
Welcome to pay attention to my public number: “procedures those things” the most popular interpretation, the most profound dry goods, the most concise tutorial, many you do not know the small skills you find!