Javascript, as we all know, is a single-threaded language in which all code must be executed in what is called a “top-down” order. The problem with this feature is that some future, unknown operations must be implemented asynchronously (which I’ll discuss in another article). This article will discuss one of the more common asynchronous solutions, Promise, which has become extremely popular by the time this article was last updated.

The problem that Promise solved

I’m sure every front-end has encountered the problem of nesting asynchronous tasks when the execution of an asynchronous task depends on the results of another asynchronous task. This can happen once or twice, but after many times your code will look like this:

	async1(function(){
		async2(function(){
			async3(function(
				async4(funciton(){
					async5(function(){
						//(╯°□°) ak47 schematic item and loot added
						/ /...}); }); ); }); });Copy the code

This is called callback hell, where the code is nested and interlocked, and it’s obvious that a slightly more complex logic would make such a program difficult to maintain.

Programmers have come up with a lot of solutions to this situation (such as modularizing code), but there is still not a lot of nesting in flow control. But last year’s ES2015 standard, the standardization of Promise, to a certain extent, solves the problem of JavaScript process operation.

Basic use of Promise

Today, many modern browsers have implemented it, but for compatibility, it is recommended that you wrap Promise yourself or use a third-party solution (such as Webpack to compile es6 syntax). So, we’ll get a Promise constructor and create a new instance of a Promise:

	var _promise = new Promise(function(resolve, reject){
		setTimeout(function(){
			var rand = Math.random();
			if(rand<0.5){
				resolve("resolve" + rand);
			}else{
				reject("reject"+ rand); }},1000);
		
	});
	
	D.js :7 Uncaught (in Promise) reject0.9541820247347901 */
	
Copy the code

As shown above, the Promise constructor accepts as a parameter a function that accepts two additional functions, resolve and reject. These two functions represent the state of the current Promise which is fulfilled and rejected, respectively. It is through these two states that Promise controls the outcome of an asynchronous operation. We’ll talk about the use of promises next. In fact, the instance _PROMISE on a Promise is an object, not a function. The argument function passed by a Promise is executed immediately upon declaration, so the correct posture for a Promise is to wrap another layer of functions around it.

	
	var run = function(){
		var _promise = new Promise(function(resolve, reject){
			setTimeout(function(){
				var rand = Math.random();
				if(rand<0.5){
					resolve("resolve" + rand);
				}else{
					reject("reject"+ rand); }},1000);
		});
		return _promise;
	}
	run();
Copy the code

This is the normal use of Promise, followed by processing of the result of the asynchronous operation, followed by the function run() created above

	run().then(function(data){
		console.log(data);
	});
Copy the code

Each Promise instance object has a then method, which is used to process the results of the previous asynchronous logic.

So, you may ask, what good is this?

Sure, we’ve learned the basic flow of Promise so far, but this usage doesn’t seem different from nested callback functions, and it adds complexity. But as we said, promises are really useful for controlling the flow of logic when multiple asynchronous operations depend on each other. Promise addresses control of the process by controlling both states. See the code below:

	run().then(function(data){
		// Handle resolve code
		cosnole.log("Promise is set to resolve",data);
	},function(data){
		// Process the reject code
		cosnole.log("Program is set to reject.",data);
	})
Copy the code

If we get the desired result from the asynchronous operation, we call resolve, which gets the data in the first anonymous parameter of then, and reject, which gets the error processing data in the second anonymous parameter of then. At this point, a sub-complete Promise call ends. For a Promise’s then() method, then always returns a Promise instance, so you can always call then, in the form of run().then().then().then().then().then(). Then ()….. When a THEN () method calls the state of asynchronous success, you can either return a definite “value” or return a Promise instance. When an exact value is returned, then passes the exact value to a default Promise instance. This Promise instance will be immediately set to a depressing state for use in the subsequent THEN method. As follows:

	run().then(function(data){
		console.log("The first time",data);
		return data;
	}).then(function(data){
		console.log("The second time",data);
		return data;
	}).then(function(data){
		console.log("The third time",data);
		return data;
	});
	/* Print the result of successful asynchronous processing: First surprised resolve0.49040459200760167 jeter s: 18 second surprised resolve0.49040459200760167 jeter s: 21 third resolve0.49040459200760167 The then method can be called indefinitely. * /
Copy the code

With this feature, we can manage asynchronous logics that depend on each other in a comparative order. Here is a long example with three asynchronous operations.

	// The first asynchronous task
	function run_a(){
		return new Promise(function(resolve, reject){
			// Assume that an asynchronous operation has taken place and data has been obtained
			resolve("step1");
		});
	}
	// The second asynchronous task
	function run_b(data_a){
		return new Promise(function(resolve, reject){
			// Assume that an asynchronous operation has taken place and data has been obtained
			console.log(data_a);
			resolve("step2");
		});
	}
	// The third asynchronous task
	function run_c(data_b){
		return new Promise(function(resolve, reject){
			// Assume that an asynchronous operation has taken place and data has been obtained
			console.log(data_b);
			resolve("step3");
		});
	}
	
	// call continuously
	run_a().then(function(data){
		return run_b(data);
	}).then(function(data){
		return run_c(data);
	}).then(function(data){
		console.log(data);
	});
	
	/* step1 step2 step3 */
	
Copy the code

This completes the dependency of several asynchronous operations, eliminating the headache of callback hell.

Asynchronous operations reject and terminate the call chain

As mentioned earlier, the THEN method can accept two anonymous functions as parameters. The first parameter is the callback after the Promise state is fulfilled, and the second parameter is the callback after the Rejected state. In many cases, if there are several asynchronous tasks in a row and one of them fails, then the next few tasks are largely unprocessed. How do we terminate the chain of calls to THEN? In Promsie, there is a catch method as well as a then method. We use the above code to modify run_a().

	// A step to modify RUN_a may be rejected
	function run_a(){
		return new Promise(function(resolve, reject){
			setTimeout(function(){
				if(Math.random()>. 5){
					resolve("step1");
				}else{
					reject("error"); }},1000);
		});
	}
	
	// This does not end
	run_a().then(function(data){
		return run_b(data);
	},function(data){
		// If you do this with the Rejected state, it does not terminate the call chain
		return data;
	}).then(function(data){
		return run_c(data);
	}).then(function(data){
		console.log(data);
	});
	
	// Add a catch method to the end of the call chain. If the asynchronous processing of a Promise fails in a link, subsequent calls will be terminated and the last catch will be skipped
	run_a().then(function(data){
		return run_b(data);
	}).then(function(data){
		return run_c(data);
	}).then(function(data){
		console.log(data);
	}).catch(function(e){
		// The state of Rejected jumps directly to the catch, and the rest of the calls do not continue
		console.log(e);
	});
Copy the code

The code above briefly describes how to terminate a chain call. It is important to note that the catch method also has the function of a try catch. In other words, if the logic in the then code fails, it is not thrown at the console.

ES6 extension of Promise/A+

Promise was put forward very early, and its standard is called Promise/A+, which has little content. ES6 has written Promise into the standard and extended it based on it. For details, please refer to:

· Translation of Promise/A+ by Malcolm Yud · Ruan Yifeng ES6 introduction — Promise

Here’s a look at ES6’s extensions to the Promise standard, or check out the reference link above

Promise. All extensions


This extension combines multiple asynchronous operations into one operation, that is, parallel processing of asynchronous operations, and finally unified operation results. Note: this method can only be called directly from a Promise object, and instances cannot perform this operation.

All () takes an array of arguments, one for each item in the array

	// The first asynchronous task
	function run_a(){
		return new Promise(function(resolve, reject){                
			// Assume that an asynchronous operation has taken place and data has been obtained
			resolve("step1")}); }// The second asynchronous task
	function run_b(){
		return new Promise(function(resolve, reject){
			// Assume that an asynchronous operation has taken place and data has been obtained
			resolve("step2");
		});
	}
	// The third asynchronous task
	function run_c(){
		return new Promise(function(resolve, reject){
			// Assume that an asynchronous operation has taken place and data has been obtained
			resolve("step3");
		});
	}
	
	Promise.all([run_a(),run_b(),run_c()]).then(function(data){
		console.log(data);
	},function(data){
		console.log(data);
	});
	/* Print the result ["step1","step2","step3"] */
	
	// Modify the second asynchronous task
	// The first asynchronous task
	function run_b(){
		return new Promise(function(resolve, reject){                
			// Assume that an asynchronous operation has taken place and data has been obtained
			reject("step2")}); }/* Prints the result * that captures the first rejected state to occur ["step2"] */
Copy the code

As shown above, the results of the parallel operation are returned in the order of the input arguments in the array.

Promise. The expansion of the race


As the name implies, a race is a series of parallel asynchronous operations in which the first one to finish is the winner.

	// The first asynchronous task
	function run_a(){
		return new Promise(function(resolve, reject){
			setTimeout(function(){
                console.log("Execute to step1");                
                resolve("step1")},3000);
		});
	}
	// The second asynchronous task
	function run_b(){
		return new Promise(function(resolve, reject){
            setTimeout(function(){
                console.log("Proceed to step2");
                resolve("step2");
            },1000);
		});
	}
	// The third asynchronous task
	function run_c(){
		return new Promise(function(resolve, reject){
            setTimeout(function(){
                console.log("Proceed to step3");
                resolve("step3");
            },3000);
		});
	}

    Promise.race([run_a(),run_b(),run_c()]).then(function(results){
        console.log(results);
    },function(data){
        console.log(data);
    });
    /* print the result: go to step2. Step2 go to step1. Go to step3
Copy the code

As you can see, run_B completes first and then calls back, but it is important to note that after the first asynchronous callback, other asynchronous operations will continue to execute, just not continue into THEN.

conclusion

The above is a simple understanding of THE Promise under THE ES6 standard. The Promise appeared for a long time and has been widely used in many open source projects. Understanding the Promise is conducive to a further understanding of the code. This article as my personal learning record, I hope to play a role in everyone’s learning.