What is Promise? Why use Promise?

When we use asynchronous invocation of JS, we are usually used to using callback functions. Such code is simple and easy to understand, but when the callback is nested, it will cause code chaos and difficult to comb out, for example:

function fun1(arg1,function(){
// dosomething 
})
Copy the code

This simple nesting is fine and easy to understand. But when there are multiple layers of nesting: all we know is that promises are the biggest benefit to avoid “callback hell,” meaning multiple layers of callbacks

function fun1(arg1,function(data1){ function fun1(arg2, function(data2){ function fun1(arg3, function(data3){ //..... })})})Copy the code

Three layers of nesting like the one above is already a hassle, let alone more layers of nesting, so to make the callbacks more obvious and the code easier to understand, use Promise to solve this problem elegantly:

Var p = new Promise(resolve (reject){}).then(function(data){}).then(function(data){}).then(function(data){}).then…

The Promise accepts a callback function, which takes two arguments: **resolve (which changes the state of the Promise from pending to depressing, which will be called if the asynchronous operation succeeds). And pass the result of the asynchronous operation), reject (changes the state of Promise from pending to Rejected, which is called when the asynchronous operation fails and passes the error of the asynchronous operation as an argument) ** These are both functions that represent success and failure handlers. Then accepts the result of the previous callback, so such a chain call makes it completely clean to implement multiple calls.

The Promise object has two characteristics: (1) The state of the object is not affected by the outside world, and the Promise has three states: This state can be decided Pending, fulfilled and rejected only by the result of an asynchronous operation. No other operation can change this state. ② once the state has changed, it will never change again. You can get this at any time. There are only two possibilities for state changes: from pending to depressing and from pending to Rejected. Just change it and it’s set.

Disadvantages: (1) Promises cannot be cancelled once they are created, and are immediately executed once they are created. (2) If you do not set a callback function, its internal errors are not reflected externally. ③ When in a pending state, there is no way to determine which stage of progress is being made (just started or almost finished).

Here’s the basic syntax for promises, starting with the Promise print

Promise.prototype has catch, then, and constructor methods. So these methods can be inherited by instances.

The Promise itself has some common methods promise.all (), promise.race (), promise.resolve (), promise.reject ().

1.Promise.prototype.then()

let promise = new Promise(function(resolve,reject){
        console.log("promise");
        resolve();
});
setTimeout(function(){
    console.log("setTimeout");
},0)
promise.then(function(){
        console.log("resolved");
})
console.log("hi");

// promise   hi   resolved  setTimeout
Copy the code

As the above code shows, promise is executed immediately after creation, then the script specified by the then method is executed after all the current synchronization tasks are completed,setTimeout is executed at the start of the next “time loop”, and then is executed at the end of the current event loop.

2. Promise. Prototype. The catch () when Promise object is used when performing a successful resolve the callback function, and then in the then further processing methods, processing when Promise object fail in there? There are two methods: ① The then method takes a second function argument, which is used to handle errors. (Not recommended) ② Handle in catch. Look at the first one:

let promise = new Promise(function(resolve,reject){ reject(); }); promise.then(function(){ console.log("resolved"); },function(){console.log("rejected")}) output rejectedCopy the code

The use of the catch

let promise = new Promise(function(resolve,reject){ reject(); }); promise.then(function(){ console.log("resolved"); }). Catch (function(){console.log("catch the reject")}) outputs catch the rejectCopy the code

Reject throws an error, catch or then catches the second argument, and resolve does not work because the state cannot be changed once it has occurred.

Errors in the Promise object have the bubbling nature of all errors that can be passed backwards until a cantch is caught. Note: In general, try not to use the second function argument of then for error handling, and try to use catch for uniform error handling.

If the Promise object does not specify error handling, internal errors do not exit the process or stop script execution, meaning that internal errors in the Promise object do not affect the execution of external code.

let promise = new Promise(function(resolve,reject){ resolve(); }); promise.then(function(){ console.log("resolved"); y+2; }) setTimeout(function() {console.log(" I appear after y+2 ")},3000)Copy the code

1. Promise.resolve() I think I should introduce this method first when I introduce the Promise method, because it will be used later. Don’t think of the state of the Promise object it generates as simply Resolved. The purpose of this method is to convert an existing object into a Promise object (depending on the case). There are four ways to convert an object to a Promise: ① The parameter is an instance of a Promise, and no changes are made. (2) The parameter is an object that contains the THEN method (thenable object for short).

Var thenable = {then: function (resolve, rejected) {resolve (42); } } let p1 = Promise.resolve(thenable); p1.then(function(data){ console.log(data); / / 42})Copy the code

After the thanable then method is executed, the state of object P1 changes to Resolved and then is executed immediately. Resolve () = reject (reject), reject (reject) = reject (reject); then =. Catch (reject); ③ When parameters do not have then methods, or are not objects at all. Var p = Promise. Resolve (” Hello “); p.then(function(s){ console.log(s); //Hello}) returns an instance of Promise that is resolved, so the then method will be executed. And the promise.resolve () argument is passed to the callback function.

④ Without any parameters, it is used to quickly generate a Promise object. var p = Promise.resolve();

2. Promise.all() This method takes multiple Promise instances as arguments and returns a new Promise instance. This is a pity. When all the Promise instances return resolve, the state of the new Promise instance will be fulfilled. At this time, the return values of P1, P2, and P3 will form an array and be passed to the callback function of the new instance. When rejecte is returned, the status of the new instance is Rejected. The return value of the first reject instance is passed to p’s callback.

The parameters that a promise accepts are instances of a promise, so how do you convert all parameters into instances of a promise? Use the promise.resolve () method above. To get a better handle on the promise.all () method, let’s do an example.

How To use Promise To output Welcome To XIAN

var p1 = Promise.resolve("Welcome");
var p2 = "To";
var p3 = new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve("XIAN");
    },1000)
})
Copy the code

Resolve is converted to a Promise object, and p2 is converted to a Promise object. P3 is itself an instance of the Promise object.

This is done perfectly with the following code:

Promise.all([p1,Promise.resolve(p2),p3]) .then(function(data){ console.log(data instanceof Array)//true console.log(data.join(" ")); }). Catch (function(e){console.log(new Error(e)); })Copy the code

The data above is an array of arguments to the Resolve function of the Promise object. Also, the order in all determines the order of output, regardless of other factors.

If a catch method is used to catch errors in all instances, a catch using the promise.all method will not be caught. But the then method in promise.all is executed. Why? Isn’t the then method of promise.all triggered when all instances return the resolve state?

When an instance reports an error, catch is used for error processing, and a new Promise instance is returned. The state of the instance will also change to resolve after catching, so all instances of promise. all will return resolve. Then triggers promise.all. The solution is to not add a catch to the instance, so the instance reject triggers the catch of promise.all, thus achieving the true meaning of promise.all.

3.Promise.race(), like promise.all, takes an array of Promise instances as arguments and generates a new Promise object. So the arguments to this method can be resolved using the promise.resolve () method.

The object of the method’s Promise is determined by the state of the first instance that returns reject or resolve. You can use what we often see is a picture load timeout prompt, so you can use this method to implement. The function that loads the image also uses the Promise object

function preloadImage(path){ return new Promise(function(resolve,reject){ var image = new Image(); image.onload = resolve; image.onerror = reject; image.src = path; })}Copy the code

The function to implement after five seconds if the image does not load out to remind the image load timeout.

Promise.race([preloadImage("/images/1.png"), New Promise(function(resolve,reject){setTimeout(function() {reject();},5000);})]). Then (function(){alert(); }). Catch (function(){alert(" image failed to load!" )})Copy the code

Do the image load in five seconds, while the image load may fail, or do the setTimeout function reject after five seconds. This allows images to complete loading to the prompt within five seconds.

4.Promise.reject() When you see this, think promise.resolve (). Promise.resolve() can generate a Promise object from the Rejected and resolve states. Promise.reject() can only generate Promise instances in the rejected state.

var arg = "Hello";
var pro1 = Promise.reject(arg);

pro1.then(function(){
    console.log("resolved");
}).catch(function(e){
    console.log(e === arg)//true
    console.log(e) //Hello
})
Copy the code
Var thenable = {then(resolve,reject){reject(' error '); } } var pro1 = Promise.reject(thenable); pro1.then(function(){ console.log("resolved"); }).catch(function(e){ console.log(e === thenable) //true conaloe.log(e); //{then: ƒ} //then:ƒ then(resolve,reject) //__proto__:Object console.log(e instanceof Object); //true })Copy the code

As you can see, the arguments to the promise.reject () method are left intact as reject arguments, and the arguments to subsequent methods are programmed. ** So instead of printing an “error” string, e is passed as a parameter in promise.reject (). It does not use the resolve or reject arguments as promise.resolve () does.