ES6 Promise Usage Summary

What is Promise

Promise is a solution to asynchronous programming. In fact, it is a constructor. It has all, reject and resolve methods, and then, catch and other methods on the prototype. (ps: what is a prototype https://blog.csdn.net/qq_34645412/article/details/105997336 )

Promise objects have the following two characteristics.

(1) The state of the object is not affected by the outside world. The Promise object represents an asynchronous operation with three states: pending, completed, and rejected. Only the result of asynchronous operation can determine the current state, and no other operation can change this state. This is also the origin of Promise. Its English meaning is "commitment", which means that other means cannot be changed.

(2) Once the state changes, it will not change again. This result can be obtained at any time. There are only two possibilities for the state of the Promise object to change: from pending to fully and from pending to rejected. As long as these two situations occur, the state will solidify and will not change again. This result will be maintained all the time. At this time, it is called resolved. If the change has occurred, you can add a callback function to the Promise object and get the result immediately. This is completely different from events. The characteristic of events is that if you miss it and listen again, you won't get results.

Let's start with a Promise

let p = new Promise(function(resolve, reject){
		//Do some asynchronous operations
		setTimeout(function(){
			console.log('Execution complete Promise');
			resolve('The data to be returned can be any data, such as the data returned by the interface');
		}, 2000);
	});

Refresh the page and you will find that the console will print directly

The execution process is as follows: an asynchronous operation, that is, setTimeout, is executed. After 2 seconds, the output "execution is completed" and the resolve method is called.

be careful! I just new an object. Without calling it, the function we passed in has been executed. This is a detail that needs attention. Therefore, when we use Promise, it is usually packaged in a function and run the function when necessary, such as:

<div onClick={promiseClick}>Start asynchronous request</div>
 
const promiseClick =()=>{
	 console.log('The click method is called')
	 let p = new Promise(function(resolve, reject){
		//Do some asynchronous operations
		setTimeout(function(){
				console.log('Execution complete Promise');
				resolve('The data to be returned can be any data, such as the data returned by the interface');
			}, 2000);
		});
        return p
	}

There is no response when refreshing the page, but it is displayed on the console after clicking

When placed in a function, it is executed only when called

So, next, we will solve two problems:

1. Why put it in a function

2. What the hell is resolve

At the end of the wrapped function, we will return the Promise object, that is, we get a Promise object by executing this function. Next, you can use the then and catch methods on the Promise object, which is the strength of Promise. See the following code:

promiseClick().then(function(data){
    console.log(data);
    //Later, you can use the transmitted data to do other operations
    //......
});

So the console output

First, the method is called to execute promise, and finally the then method of promise is executed. The then method is a function that accepts a parameter and accepts the data returned by resolve. This outputs' the data to be returned can be any data, such as the data returned by the interface '

At this time, you should understand that the function in then has the same meaning as our usual callback function, and can be executed after the asynchronous task of promiseClick is completed. This is the function of Promise. In short, it can separate the original callback writing method, and execute the callback function by chain call after the asynchronous operation is executed.

You may feel that there is no difference between this and writing a callback function; So, what if there are multiple callbacks? What if callback is also an asynchronous operation and a corresponding callback function is required after execution? You can't define a callback 2 and pass it to the callback. The advantage of Promise is that it can continue to write the Promise object and return in the then method relay, and then continue to call then for callback operation.

Therefore, the essence of Promise is that Promise can only simplify the writing of layers of callback. In essence, the essence of Promise is "state". The callback function can be called in time by maintaining and transferring the state. It is much simpler and more flexible than passing the callback function. So the correct scenario for using Promise is as follows:

promiseClick()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});

In this way, the contents of each asynchronous callback can be output in sequence every two seconds. The data passed to resolve in runAsync2 can be obtained in the next then method.

(Ps: it is executed many times here because I performed it in a react demo when studying this usage. The page is rendered many times due to the change of multiple elements of the page. If the normal page is rendered only once, all will be executed only once.)

Usage of reject

The above explains the resolve usage of promise, which is equivalent to that resolve is a callback when promise succeeds. It modifies the state of promise to

fullfiled,So, reject It's the callback when he fails. He puts promise The status of is changed to rejected,So we're then Can be captured in, and then execute a callback for the "failed" situation.
function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved Successful callback');
			console.log('Accepted values for successful callback:',data);
		}, 
		function(reason){
			console.log('rejected Failed callback');
			console.log('Failed to execute callback throw failure reason:',reason);
		}
	);	

Execution results:

(PS: it is also executed multiple times here, so it is output multiple times. The reason for executing multiple times is the same as that of the last time.)

The above code: call the promiseClick method for execution, and obtain a random number after 2 seconds. If it is less than 10, we are successful. Call resolve to modify the state of Promise to fullfile. Otherwise, we think it is "failed". We call reject and pass a parameter as the reason for the failure. And change the status to rejected

Run promiseClick and pass two parameters in then. These two parameters are two functions respectively. The then method can accept two parameters, the first corresponding to the callback of resolve and the second corresponding to the callback of reject. (that is, the then method accepts two callbacks, a successful callback function and a failed callback function, and can get the successful data and the reason for the failure in the callback function). Therefore, we can get the data transmitted from success and failure respectively, and there will be above operation results

catch usage

A method parallel to the Promise object method then method is catch. Similar to try catch, catch is used to catch exceptions, that is, it is the same as the callback of the second parameter rejected accepted in the then method, as shown below

function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved Successful callback');
			console.log('Accepted values for successful callback:',data);
		}
	)
	.catch(function(reason, data){
		console.log('catch reach rejected Failed callback');
		console.log('catch Failed to execute callback throw failure reason:',reason);
	});	

Execution results:
The effect is the same as that written in the second parameter of then. It outputs the reason for the failed callback when it is greater than 10. However, it has another function: when executing the resolve callback (that is, the first parameter in then above), if an exception is thrown (the code is wrong), it will not report an error stuck js, but will enter the catch method. As follows:

function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved Successful callback');
			console.log('Accepted values for successful callback:',data);
			console.log(noData);
		}
	)
	.catch(function(reason, data){
		console.log('catch reach rejected Failed callback');
		console.log('catch Failed to execute callback throw failure reason:',reason);
	});	

Execution results:

In the callback of resolve, we call console log(noData); The NoData variable is undefined. If we don't use Promise, the code will directly report an error on the console and won't run down. But here, you will get the result shown in the figure above, that is, it goes into the catch method and passes the error reason to the reason parameter. Even if there is an error code, it will not report an error

Usage of all

Another method at the same level as then, the all method, provides the ability to execute asynchronous operations in parallel, and executes the callback only after all asynchronous operations are executed and the execution results are successful.

Make two copies of the above method and rename promiseclick3(), promiseclick2(), and promiseclick1(), as follows

function promiseClick1(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
	   function promiseClick2(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
	   function promiseClick3(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
 
	Promise
		.all([promiseClick3(), promiseClick2(), promiseClick1()])
		.then(function(results){
			console.log(results);
		});

Promise.all to execute. All receives an array parameter. This group of parameters are all methods that need to perform asynchronous operations, and the values in them are finally returned to the promise object. In this way, the three asynchronous operations are executed in parallel, and they will not enter then until they are all executed. So where is the data returned by the three asynchronous operations? They are all in then. All will put the results of all asynchronous operations into an array and send them to then, and then execute the successful callback of then method to receive the results. The results are as follows: (execute the results respectively, all executes the three functions uniformly, and saves the values in an array and returns them to then for callback output):

In this way, you can use all to perform multiple asynchronous operations in parallel and process all the returned data in a callback. For example, when you need to prepare all the data in advance to render the page, you can use all to perform multiple asynchronous operations to process all the data before rendering

Usage of race

All is to wait until all asynchronous operations are executed before executing the then method, so the race method is the opposite. Whoever completes the execution first will execute the callback first. No matter whether the successful callback or the failed callback of race is performed, the rest will not enter any callback of race

We change the delay of the above method to 234 seconds respectively

function promiseClick1(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('2s Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('2s The number is too 10. A failed callback is about to be executed');
				}
			}, 2000);
		   })
		   return p
	   }
	   function promiseClick2(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('3s Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('3s The number is too 10. A failed callback is about to be executed');
				}
			}, 3000);
		   })
		   return p
	   }
	   function promiseClick3(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //Generate random numbers of 1-10
				console.log('4s Values generated by random numbers:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('4s The number is too 10. A failed callback is about to be executed');
				}
			}, 4000);
		   })
		   return p
	   }
 
	Promise
		.race([promiseClick3(), promiseClick2(), promiseClick1()])
		.then(function(results){
			console.log('success',results);
		},function(reason){
			console.log('fail',reason);
		});

After 2s, promiseClick1 has entered the callback in then. When the callback in then starts to execute, promiseClick2() and promiseClick3() do not stop, but still execute again. So after another 3 seconds, their respective values are output, but they will not enter any callback of race. As shown in Figure 2s, after generating 10 successful callbacks into race, other functions continue to execute, but will not enter any callbacks of race again. 2s generates 16 failed callbacks into race, and the rest continue to execute, but will not enter any callbacks of race again.


For example, the use of race can use the then method if a request is successful within 10s. If no request is successful within 10s, enter the reject callback to perform another operation.

Add: (someone asked me how to use race. For example, if a request is successful within 10s, I can use the then method. If no request is successful within 10s, I enter the reject callback to perform another operation. I think my expression is a little problematic. Let me give an example.)

 //Request a table data
    function requestTableList(){
        var p = new Promise((resolve, reject) => {
               //Go to the background to request data. This can be ajax, axios or fetch 
                resolve(res);
        });
        return p;
    }
  //The delay function is used to time the request for 10s
      function timeout(){
          var p = new Promise((resolve, reject) => {
              setTimeout(() => {
                  reject('request timeout');
              }, 10000);
          });
          return p;
      }
      Promise.race([requestTableList(), timeout()]).then((data) =>{
        //Successful callback processing
        console.log(data);
      }).catch((err) => {
        // Failed callback processing
          console.log(err);
      });

Request an interface data, display the data when the request is completed within 10s, and prompt the request failure if the request is not completed within 10s

Here, two promises are defined, one to request data and the other to record time for 10s. Throw the two promises into the race. If the requested data runs first, enter directly then successfully callback and display the requested data; If the timing runs first, that is, 10s, and the data request is not successful, enter the failure callback of race first, and prompt the user that the data request fails catch callback, (ps: or enter the failed callback of reject. When there is no reject callback written in. then, the failed callback will directly enter. catch)

(original link: https://blog.csdn.net/qq_34645412/article/details/81170576)

Keywords: Javascript Front-end ECMAScript

Added by auro on Tue, 25 Jan 2022 17:36:13 +0200