Promises are one of the most common interview questions and a useful and central new feature in ES6. Prmoise shows its powerful and elegant nature, especially in today’s world of more and more complex asynchronous operations. In this article, we’ll take a systematic look at the core of promises.
This article has been synchronized toMy personal homepage. Welcome to visit for more content! Please feel free to discuss any mistakes or shortcomings. Thank you for your attention and support!
In this article, we step into Promise by following the following ideas:
- What is Promise? (What)
- Why do WE need Promise? Or what does Promise do? (Why)
- How do I use Promise? (How)
- Other methods of Promise.
What is Promise
Promise is an asynchronous programming solution that allows asynchronous operations to be expressed in a synchronous flow. It makes more sense than the traditional method of handling asynchronous problems with callbacks and events, and is more in line with the logic of people handling problems in a linear manner. Syntactically, a Promise is an object that holds the state and result of an event (typically an asynchronous operation) that will happen in the future.
It sounds abstract, it’s all conceptual. So why do promises appear in ES6? Concrete examples can help us better understand what promises are.
Why do WE need Promise? What is it used for?
Before ES6 comes up with promises, we handle an asynchronous request, usually something like this:
// Many asynchronous request methods also design events to process the result of an asynchronous request.function(resData) {// Process the request result});Copy the code
That seems fine, but the demands are varied and even perverted. What if we need to make a second request after the first one returns the result? And what if, after the second request comes back, we need to make a third request? And then a fourth… The fifth… At this point, the code should look like this:
asyncRequest1(function(resData1) {
asyncRequest2(function(resData2) {
asyncRequest3(function(resData3) {
asyncRequest4(function(resData4) {
asyncRequest5(function(resData5) { // ...... // process the request result}); }); }); }); });Copy the code
At this point, the code nesting level is too deep, plus we should have to do some logical processing at the end of each request, so that each place to process the result of the request additional code, the whole code block is bloated, not elegant! Most of all, such code is error-prone, difficult to locate, and laborious to read and maintain.
This is where asynchronous programming is most frustrating and unspeakable: the “callback hell” that results from nesting asynchronous operations too deeply!
When this happens, you need to think about new approaches to asynchronous programming. Is there a way to solve this nested callback hell while meeting the requirements of the above example? Can we use chained callbacks instead of nested callbacks? There has to be, and that’s where Promise comes in. In the meantime, isn’t it best to handle asynchronous requests without using callbacks? Yes, of course, this is async/ AWIat, which we will talk about later in this article.
Let’s see, in the example above, what happens if we use Promise to implement it? It should look like this:
new Promise(asyncRequest1)
.then(asyncRequest2(resData1))
.then(asyncRequest3(resData2))
.then(asyncRequest4(resData3))
.then(asyncRequest5(resData4))
.catch(handleError(errorMsg))
Copy the code
In the example above, the next.then() method is entered only if each step asyncRequest successfully returns the result, thus making the next asynchronous request…… And so on. When an error occurs in any of the requests, it goes into the.catch() method, where the error can be handled. Such chained callbacks satisfy the requirements of the previous example while avoiding nested callbacks, thus avoiding “callback hell.”
Here specific grammar can not understand, never mind! Don’t panic! This example is just to illustrate how Promise solves nested callback hell with chained callbacks. Now, let’s talk about how to use Promise and its basic syntax.
How to use Promise
1. Create a Promise object instance
As specified in ES6, a Promise is a constructor that can be used to instantiate a Promise object. Here’s a simple example:
// The Promise constructor takes a function as an argumentlet promise = new Promise(Function);
Copy the code
2. State and change of Promise
A Promise is an object that holds the state and result of an event (usually an asynchronous operation) that will happen in the future.
Let’s start by looking at the states that Promise represents for asynchronous operations. — There are only three states:
- Pending
- This is a big pity.
- Rejected (failed)
These three states, they don’t co-exist, and Promise can only be in one of them. An asynchronous request is in a pending state when it starts and does not end (with no result returned). After the asynchronous request returns the result, you can change the state of the Promise to fulfilled or Rejected according to the result returned by the request. And once a Promise’s state changes for the first time, it can never change to any other state. Therefore, there are only two cases of Promise state change:
- This is a pity that is pending –> has been successfully fulfilled.
- Pending –> Rejected (Failed)
So, how do you change the state of a Promise? This requires understanding the Function argument passed to the Promise constructor when it is called. Promise sets two parameters to this function, resolve and reject. These two parameters are two functions that are provided by the JavaScript engine and do not need to be deployed.
The resolve() function can change the state of a Promise from pending to fulfilled. Reject (), which changes the state of a Promise from Pending to Rejected.
Two caveats here!!
- in
Promise
The interior is only forresolve()
,reject()
In order to change its state.return
Any value (including an Error instance) does not change its state.throw
Any value will cause an error! resolve()
,reject()
andreturn
Have different meanings. They just changedPromise
Does not end code execution. That is to say,resolve()
,reject()
The subsequent code will still execute. (Although it is not recommended to have code after them)- In the definition
Promise
Any synchronous code other than the asynchronous operation in the argument function is executed immediately.
Take a look at an example to understand the above text simply and clearly.
let promise = new Promise(function(resolve, reject) {// The next two lines execute immediately, without waiting for the asynchronous operation to return and the state to changelet a = '123';
console.log(a); // '123'// asyncRequest(function(resData) {
ifThis will be a big pity. (/* asynchronous operation succeeds */){// This will be a big pity. // resData is usually the result of an asynchronous operation}else{// Change the state of Promise to Rejected (rejected) (reject(resData)); // resData is usually some error message}}); });Copy the code
In the example above, an asynchronous request is made within the Promise, and when the request is completed and the return value resData is returned, the state of the Promise can be modified according to the specific business requirements.
3. Promise saves the result of an asynchronous operation
Any observant student will notice that in the above example, we pass resData in resolve() and reject(). What do we do? Remember? Promise stores not only the state of an asynchronous operation, but also the result of an asynchronous operation. We will pass resData, the result of the asynchronous operation, to these two functions, saving it in the Promise object.
4. Retrieve states and results from promises (.then()/.catch()))
So how do we get the final state and result of an asynchronous operation that is stored in a Prmoise object? In other words, how do we know what the state and result of an asynchronous operation are?
In fact, each Promise object instance will have a.then() and.catch() methods, both of which take a function as an argument that the Promise passes in as an argument, This parameter is the result of the asynchronous request passed in the resolve(), reject() methods (resData in the previous example). This is very depressing. When the Promise’s internal state becomes fulfilled, it will enter the. Then () method and execute the callback function inside. Similarly, when the internal state of the Promise changes to Rejected, the.catch() method is entered and its callback is executed.
/*** / promise. Then (function(resData) {// The promise state becomes progressively, perform console.log(resData) here; }).catch(function(resData) {// The promise state changes to Rejected, console.log(resData); });Copy the code
This is a big pity. When the implementation enters. Then (), it will be a pity. If you enter.catch(), the status is rejected, and error processing is done here. At the same time, the results of asynchronous operations are passed into functions defined inside.then() and.catch(), which can be accessed directly.
Then ()/.catch()
The return value of ** in.then()/.catch() is still a Promise instance. Then ()/.catch() any return value is converted to a Promise instance. So.then() can be chain-called. Then ()/.catch,.catch() can be chain-called. Thus, it is possible to have code like this:
// This code is perfectly fine. promise.then(function(resData) {// some code}).then(function(resData) {// some code}).catch(function(error) {// some code}).then(function(resData) {// some code}).catch(function(error) {// some code});Copy the code
Here are some caveats!!
- Before a
.then()
In thereturn
Any value (including oneError
Instance), will go to the nearest one behind.then()
. - Before a
.then()
In thethrow
Any value or internal code error goes to the next nearest.catch()
. - In the same way,
.catch()
In the case with.then()
Exactly the same.
Other methods of Promise
1, Promise. Resolve ()
The promise.resolve method takes an arbitrary value as a parameter that can be converted into a Promise object.
The method can be divided into the following four different cases:
(1) The argument is an instance of Promise
At this point, the promise. resolve method does no conversion and returns the instance intact.
(2) The argument is a Thenable object
The Thenable object is an object that implements the THEN method inside the object. At this point, the promise.resolve method first converts the object to a Promise object and then immediately executes the parameter object’s own then method.
And finally, convert toPromise
The state of an object depends entirely on its interiorthen
The concrete implementation of a method, not necessarilyfulfilled
State, it could berejected
.
// Define a thenable objectlet thenable = {
then: function(resolve, reject) { resolve(42); // If you execute the following line of code, it is followed by.catch() // reject()'error'); }};let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
}).catch(function(value) {
console.log(value); // 'error'
});
Copy the code
(3) The argument is not a Thenable object, or is not an object
The Promise. Resolve method returns a new Promise object, which is fulfilled, if the parameter is not a Thenable object, or if it is not an object. The Promise.
Promise.resolve('foo'New Promise(resolve => resolve();'foo'));
let p = Promise.resolve('Hello');
p.then(function (s){
console.log(s); // 'Hello'
});
Copy the code
(4) No parameters are passed
The Promise. Resolve method allows invocation with no parameters and directly returns a fulfilled Promise object, which holds undefined.
let p = Promise.resolve();
p.then(function (value) {
console.log(value); // undefined
});
Copy the code
2, Promise. Reject ()
The promise. reject method also returns a new Promise instance. The instance must be in the rejected state with or without the Thenable method, regardless of the data type of the parameter passed in. Reject, and the value stored in the returned Promise object is the same as the parameter value when the promise. reject method was passed in.
Example alet p = Promise.reject('error'); / / is equivalent tolet p = new Promise((resolve, reject) => reject('error')); 2 / / exampleslet thenable = {
then(resolve, reject) {/** * the state of the Promise object is rejected, and the state of the Promise object is rejected.'error');
// resolve('fulfilled'); }}; Promise.reject(thenable).then(data => {// will not enter here!! console.log('Enter then! ');
}).catch(e => {
console.log('Enter the catch! '); / /! Attention! The value of e here is the thenable object console.log(e === thenable) passed into the promise.reject () method; //true
})
Copy the code
2, Promise. All ()
The promise.all method is used to wrap multiple Promise instances into a new Promise instance.
let p = Promise.all([p1, p2, p3]);
Copy the code
The promise. all method takes an array of elements p1, P2, and p3 as Promise instances. If not, the promise.resolve () method is first called, the argument is turned into a Promise instance, and further processing is done.
Finally, the state of P is jointly determined by P1 / P2 / P3, which can be divided into two cases:
- only
p1
/p2
/p3
The state of theta becomesfulfilled
.p
Will becomefulfilled
. At this timep1
/p2
/p3
To form an array of return values passed top
The callback function of. - As long as
p1
/p2
/p3
One of them wasrejected
.p
The state of theta becomes thetarejected
. Now the first one to bereject
Is passed top
The callback function of.
2, Promise. Race ()
The promise.race method also wraps multiple Promise instances into a new Promise instance.
let p = Promise.race([p1, p2, p3]);
Copy the code
The promise.race method receives the same parameters as the promise.all method. If it is not a Promise instance, the promise.resolve () method is first called to turn the parameters into a Promise instance, and further processing takes place.
In the example above, the state of P changes as long as any of the instances of P1 / P2 / P3 change their state first, regardless of which state they change. The return value of the first Promise instance to change state is passed to p’s callback.
link
Interview Promise – This article is also very well written, and I recommend reading it in combination with some references.