1. What is Promise

Promise is a solution for asynchronous programming. It is actually a constructor with its own methods all, reject and resolve, and prototype methods such as then and catch.

The Promise object has the following two features:

  1. The Promise object represents an asynchronous operation with three states: pending, fulfilled and rejected. only the result of the asynchronous operation can determine which state it is currently in. No other operation can change this state. This is where the name Promise comes from.
  2. Once the state has changed, it will not change again. There are only two possibilities for a Promise object to change state: from pending to fulfilled and from pending to rejected; as soon as either of these happens, the state is frozen and will never change again, and the result will remain the same, which is called resolved. If the change has already happened, you will also get this result immediately if you add a callback function to the Promise object. This is completely different from an Event, which is such that if you miss it and then listen for it, you won’t get the result.

Let’s start with a new Promise:

let p = new Promise(function(resolve, reject){
		// do some asynchronous operations
		setTimeout(function(){
			console.log('Promise Execution Complete');
			resolve('The data to be returned, which can be any data e.g. interface return data');
		}, 2000);
	}); 

Refresh the page, the console will output: Promise Execution Complete

The procedure is: the program performs an asynchronous operation, setTimeout. 2 seconds later, it outputs “promise execution complete” and calls the resolve method.

Note: I just created an object, I didn’t call it. The function we passed in has already been executed. This is a detail to be aware of. So when we use Promise we usually wrap it in a function and run it when we need it,
e.g:

<div onClick={promiseClick}>Begin Async Request</div>
 
const promiseClick =()=>{
	 console.log('click to call the function')
	 let p = new Promise(function(resolve, reject){
		setTimeout(function(){
				console.log('execution complete');
				resolve('returned data');
			}, 2000);
		});
        return p
	} 

There is no reflection when the page is refreshed, but after clicked, the console outputs:
click to call the function
execution complete

2. Resolve

Our wrapped function, at the end, will return a Promise object. In other words, by executing this function we get a Promise object. The next step is to use the then and catch methods of the Promise object. This is where the power of Promise comes in. Look at the following code:

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

The console will output:
click to call the function
execution complete
returned data

This is where Promise comes in. In simple terms, it is the ability to separate out the original callback writing and execute the callback function in a chained call after the asynchronous operation has been executed.

You may think that there is no difference between this and writing a callback function. So, what if there are multiple layers of callbacks? You can continue to write the Promise object in the then method and return it, and then continue to call then to perform the callback operation.

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

The console will output:
click to call the function
execution complete
returned data
click to call the function2
execution complete2
returned data2
click to call the function3
execution complete3
returned data3

3. Reject

Reject is the callback on failure. It changes the state of the promise to rejected so that we can catch it in then and execute the callback for the “failure” case.

function promiseClick(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num is larger than 10');
			}
		}, 2000);
	    })
	return p
}
 
promiseClick().then(
	function(data){
		console.log('resolved');
		console.log('returned value:',data);
	}, 
	function(reason){
		console.log('rejected');
		console.log('fail reason:',reason);
	}
);	 

The output will be:
random value: 15
rejected
fail reason: num is larger than 10
random value: 8
resolved
returned value: 8

The then method can take two arguments, the first corresponding to the callback for resolve and the second corresponding to the callback for reject. (This means that the then method accepts two callbacks, a success callback and a failure callback, and can get the success data and the reason for the failure in the callback function.) So we can get the success and failure data separately and we have the above runtime result.

4. Catch

A parallel to the then method of the Promise object is catch. Similar to try catch, catch is used to catch exceptions, i.e. the same callback as the second argument rejected accepted in the then method, as follows:

function promiseClick(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num is larger than 10');
			}
		}, 2000);
	    })
	return p
}
 
promiseClick()
.then(
	function(data){
		console.log('resolved');
		console.log('returned value:',data);
	})
.catch(
    function(reason, data){
	    console.log('catch rejected');
	    console.log('catch fail reason:',reason);
    });	 

It also serves another purpose: if an exception is thrown (an error in the code) when executing the resolve callback (the first argument in then above), it will not report an error and terminate the program, but will instead go to this catch method.

5. All

This method provides the ability to execute asynchronous operations in parallel. The callback is only executed when all asynchronous operations have been executed and the results are all success.

function promiseClick1(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num is larger than 10');
			}
		}, 2000);
	    })
	return p
}

function promiseClick2(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num is larger than 10');
			}
		}, 2000);
	    })
	return p
}

function promiseClick3(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num is larger than 10');
			}
		}, 2000);
	    })
	return p
}

Promise
    .all([promiseClick1(), promiseClick2(), promiseClick3()])
    .then(function(results){
			console.log(results);
	}); 

All takes an array of arguments for all the methods that need to perform asynchronous operations, the values of which are eventually returned as Promise objects.
Inside then, all puts the results of all the asynchronous operations into an array and passes to then.

6. Race

The all method waits for all asynchronous operations to be executed before executing the then method, but the race method is the opposite. Whoever finishes first executes the callback first. Whoever finishes first, regardless of whether they make a success callback or a failure callback, the rest will not make any callbacks to the race method.

Let’s change the delay of above codes to 2, 3 and 4 seconds:

function promiseClick1(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value1:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num1 is larger than 10');
			}
		}, 2000);
	    })
	return p
}

function promiseClick2(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value2:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num2 is larger than 10');
			}
		}, 3000);
	    })
	return p
}

function promiseClick3(){
	let p = new Promise(function(resolve, reject){
		setTimeout(function(){
			var num = Math.ceil(Math.random()*20); 
			console.log('random value3:',num)
			if(num<=10){
				resolve(num);
			}
			else{
				reject('num3 is larger than 10');
			}
		}, 4000);
	    })
	return p
}

Promise
    .race([promiseClick1(), promiseClick2(), promiseClick3()])
    .then(function(result){
		console.log(result);
	}, function(reason){
	    console.log(reason)
	}); 

The output will be:
random value1: 8
8
random value2: 10
random value3: 1
OR
random value1: 12
num1 is larger than 10
random value2: 4
random value3: 9

We can see, after 2 seconds, promiseClick1 finished and the program entered the then function. And promiseClick2 and promiseClick3 continue to execute. But they will not enter the then function.

Supplementary Example:

set timeout to a request with Promise.race

function requestTableList(){
    var p = new Promise((resolve, reject) => {
        // request data with axios or fetch
        resolve(res);
    });
    return p;
}

// delay function
function timeout(){
    var p = new Promise((resolve, reject) => {
        setTimeout(() => {
             reject('Request Timeout.');
        }, 10000);
    });
    return p;
}

Promise.race([requestTableList(), timeout()])
.then((data) =>{
    // request success
    console.log(data);
})
.catch((err) => {
    // failure callback
    console.log(err);
}); 

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

Catalogue