What is Promise
1. Know Promise:
Promise is a solution for asynchronous operation.
Let's talk about asynchronous first:
The callback function is actually an asynchronous operation, for example:
document.addEventListener( 'click', () => { console.log('This is asynchronous'); }, false ); console.log('This is synchronous');
2. When to use Promise:
Promise is generally used to solve the problem of nested callback functions (callback hell).
Insert code slice here
Basic usage of Promise:
1. Instantiate constructor to generate instance object:
Promise solves not the callback function, but the callback hell, that is, it is not that you can't use the callback function with promise. They can coexist.
// Instantiate constructor to generate instance object: const p = new Promise(() => {});
2. Promise status:
Promise's state solves a series of behaviors of promise. Promise has three states. At the beginning, it is pending. It executes resolve and becomes fully resolved. It has been successful; Execute reject and become rejected, which has failed; Once the promise state changes, it will not change again.
The beginning is pending:
const p = new Promise((resolve, reject) => { }); console.log(p); // Promise {<pending>
Execute resolve and become fully (resolved) successfully:
const p = new Promise((resolve, reject) => { resolve(); }); console.log(p); // Promise {<fulfilled>: undefined}
Execute reject, become rejected, failed:
const p = new Promise((resolve, reject) => { reject(); }); console.log(p); // Promise {<rejected>: undefined}
But please note here: the first parameter in Promise is the callback function in success status, and the second parameter is the callback function in failure status. Resolve and reject in Promise are only formal parameters (names can be written casually, and they can be named as they think of). The reason why they are written as resolve and reject is to make them more semantic. Then, What is the result of the following code execution
const p = new Promise((r1,r2) => { r2(); }); console.log(p);
Because r1 and r2 are only formal parameters and the second parameter is the callback function in failure state, calling r2 is equivalent to calling the callback function in failure state. Therefore, there is no doubt that the result is promise {< rejected >: undefined}. Here is just a reminder. Don't get confused.
Once the Promise state changes, it will not change again:
const p = new Promise((resolve, reject) => { resolve(); reject(); }); console.log(p); // Promise {<fulfilled>: undefined}
3. then method (brief description, details will be described later):
Here, then passes two functions. Use the first function if you succeed and the second function if you fail.
// Failed: const p = new Promise((resolve, reject) => { reject(); }); p.then( () => { console.log('success'); }, () => { console.log('error'); } ); // error
// success: const p = new Promise((resolve, reject) => { resolve(); }); p.then( () => { console.log('success'); }, () => { console.log('error'); } ); // success
4. Parameters of resolve and reject functions:
The parameters of the resolve and reject functions will be passed to the formal parameters of the function in the corresponding then method, that is, resolve() passes its parameters to the formal parameters of the first function in then, and reject() passes its parameters to the formal parameters of the second function in then; give an example:
// When successful: const p = new Promise((resolve, reject) => { resolve({username:'Alex'}); }); p.then( data => { console.log('success', data); }, err => { console.log('error', err); } ); // success {username: "alex"}
// In case of failure: const p = new Promise((resolve, reject) => { reject(new Error('reason')); }); p.then( data => { console.log('success', data); }, err => { console.log('error', err); } ); // error Error: reason // at 2-2.Promise basic usage html:28 // at new Promise (<anonymous>) // at 2-2.Promise basic usage html:16
then method:
1. When to execute:
When pending - > fully, execute the first callback function of then
When pending - > rejected, execute the second callback function of then
2. Return value after execution:
The then method returns a new Promise object after execution.
const p = new Promise((resolve, reject) => { resolve(); // reject(); }); const p2 = p .then( () => {}, () => {} ) .then() // Because the then method returns a promise, you can add the then method later. .then(); console.log(p, p2, p === p2); // Promise {<fulfilled>: undefined} Promise {<pending>} false
3. The state of Promise object returned by then method changes:
As mentioned earlier, the promise of the first new can determine the execution callback function next to then, for example:
const p = new Promise((resolve, reject) => { reject(); }); p.then( () => { console.log('success'); }, () => { console.log('err'); }); // err
Because reject() is executed in P, the second callback function of then next to p is executed, so err is output,
We all know that the then method can continue to be used behind the previous then method, but have you ever thought about how the new then method is implemented? Let's explain:
Before explaining, let's judge the printed value of the following code?
// Case 1: const p = new Promise((resolve, reject) => { reject(); }); p.then( () => { console.log('success'); }, () => { console.log('err'); }).then( data => { console.log('success2', data); }, err => { console.log('err2', err); } )
This value is err success2 undefined,
Let me first give you an analysis of the implementation of reject() in p, so in the first then to execute second callback functions, so print out err, and then in the first then is always returned to the successful state of the Promise object is always successful, so in the second then calling the first callback function, so print out success2 undefined. It can be seen from this that whether the later then executes the first callback function or the second callback function depends on the previous then. Maybe you are right
In the first then, the Promise object in success status is always returned by default
I don't quite understand this sentence. Let me demonstrate it to you through code:
Let's take a look at the code:
// In the callback function of then, the things behind return will be wrapped with Promise return undefined; // Equivalent to return new Promise(resolve => { resolve(undefined); });
This is a detailed explanation:
1. There is a return value in all functions. If it is not written, it will return undefined by default. Therefore, undefined will be returned by default in the first then (equivalent to a line of code with return undefined by default in the program)
() => { console.log('err'); // By default, there is return undefined here; Such a line of code })
And because the Promise object in success status is always returned by default, that is:
() => { console.log('err'); // By default, there is return undefined here; Such a line of code // Because the Promise object in success status is always returned by default, it is equivalent to a new Promise executing resolve(), that is: return new Promise((resolve, reject) => { resolve(undefined); // Because undefined is returned by default, the parameter in resolve is undefined })
Because the previous then executes resolve, the first callback function will be executed at the second then, so it prints success2 undefined, which is because the undefined passed in by reject in a then. At this point, you may ask: by default, the Promise object in the successful state is always returned, so how to return the Promise object in the failed state? In fact, the default in then is to return the Promise object that is always in the success state. Then I directly give a Promise in the failure state, so there will be no default value again. Yes, that's it. give an example:
const p = new Promise((resolve, reject) => { reject(); }); p.then( () => { console.log('success'); }, () => { console.log('err'); / return new Promise((resolve, reject) => { reject('reason'); }); / }).then( data => { console.log('success2', data); }, err => { console.log('err2', err); } )
You should pay attention to the two lines of code in the horizontal line, that is, the program will no longer execute the Promise object in the default correct state, but execute the wrong Promise object written by itself (i.e. / the middle code). Therefore, the execution result of this case is: err err2 reason, and the principle is the same as that of case 1.
Then simply test whether you have mastered the above knowledge. Last case:
const p = new Promise((resolve, reject) => { reject(); }); p.then( () => { console.log('success'); }, () => { // Step 1: console.log('err'); }).then( data => { // Step 2: console.log('success2', data); }, err => { console.log('err2', err); } ).then( data => { // Step 3: console.log('success3', data); }, err => { console.log('err3', err); } );
As long as you understand the above knowledge, this case is a piece of cake. The answer is: err success2 undefined success3 undefined. The implementation is step 1, step 2 and step 3 respectively.
catch method:
1. What's the use:
In the previous then method, we know that it has two callback functions (the first one deals with the successful state and the second one deals with the failed state). However, in actual development, then only deals with the successful state, so only one callback function is transmitted. Therefore, catch is specially used to deal with the failed state, that is, catch is essentially a special case of then, Then (null, err = > {});
2. Basic usage:
new Promise((resolve, reject) => { // resolve(123); reject('reason'); }).then(data => { console.log(data); // then handle the correct state }).catch(err => { console.log(err); // Status of catch processing error }) // reason // The catch above is actually equivalent to .then(null, err => { console.log(err); });
catch() can catch the errors in front of it. It is generally recommended that the Promise object should be followed by the catch method, so as to deal with the errors inside Promise:
Catch can catch the previous error. If the error is caught by catc, the error disappears. In addition, catch also returns a Promise object in success status by default (the reason is very simple. The essence of catch is then, because then returns the Promise object in success status by default, so catch is also the Promise object in success status). Therefore, then followed by catch will only execute successful callback functions, If you want to execute the callback function in the failed state, you need to manually return the Promise object in the failed state. In addition to this method, there is another method. See the code:
new Promise((resolve, reject) => { // resolve(123); reject('reason'); }) .then(data => { console.log(data); }) ///First piece .catch(err => { console.log(err); throw new Error('reason'); }) .then(data => { console.log(data); }) Second piece .catch(err => { console.log(err); }); / // reason // Error: reason
Reason is the result of the execution of the first code, and Error: reason is the result of the execution of the second code. If an error is thrown in the first block of code, it will be caught by the catch in the second block of code. In this way, the callback function of success status in then will no longer be executed.
Promise.resolve() and promise reject():
1,Promise.resolve():
Is a short form of success status Promise.
new Promise(resolve => resolve('foo')); // resolve in this place is a formal parameter, and the name can be written as you want // Abbreviation Promise.resolve('foo'); // resolve here is a fixed method name and cannot be scribbled
Parameters:
(1) General parameters (most important):
Promise.resolve('foo').then(data => { console.log(data); }); // foo
(2) Special parameters (simply understand it, don't delve into it):
1. Pass Promise as a parameter.
const p1 = new Promise(resolve => { setTimeout(resolve, 1000, 'I did'); }); Promise.resolve(p1).then(data => { console.log(data); }); // I did (Note: print in a second)
Why? The reason is: when Promise When resolve () receives a Promise object, it directly returns the Promise object and does nothing.
That is, the above code is equivalent to:
const p1 = new Promise(resolve => { setTimeout(resolve, 1000, 'I did'); // The above setTimeout is equivalent to: // setTimeout(() => { // resolve('I executed '); // }, 1000); }); p1.then(data => { console.log(data); }); // I did (Note: print in a second) console.log(Promise.resolve(p1) === p1); // true
In addition, when the resolve function receives a Promise object, the subsequent then will decide which callback to execute according to the state change of the delivered Promise object.
Described in the above code:
const p1 = new Promise(resolve => { setTimeout(resolve, 1000, 'I did'); }); new Promise(resolve => resolve(p1)).then(data => { console.log(data); });
The above sentence means that if the function receives a Promise object (i.e. p1 of the above code), the subsequent then is dominated by p1, because p1 executes resolve('I executed ') one second later; So I sent a 'I executed' message to then, so then printed it out after execution.
2. Object with then method:
Because this form is not very useful in practical development, we won't talk about it in detail here. As you know, it's OK to have this thing. (if you encounter it, you'll be finished by directly checking the document)
2,Promise.reject():
A short form of failure state Promise.
new Promise((resolve, reject) => { reject('reason'); }); // Equivalent to Promise.reject('reason');
Parameters:
No matter what parameters are, they will be passed back intact as parameters of subsequent methods. (much simpler than resolve)
There is also a promise Resolve() and promise Reject() is used in the return of the then method, for example:
new Promise((resolve, rejcet) => { resolve(123); }) .then(data => { // return data; // return Promise.resolve(data); // Short for promise object in failed state return Promise.reject('reason'); // Short for Promise object in failed state }) .then(data => { console.log(data); }) .catch(err => console.log(err)); // reason
Promise.all():
1. What's the use:
Promise.all() focuses on the state changes of multiple promise objects; You can pass in multiple promise instances in the promise object and wrap it into a new promise instance to return.
2. Basic usage:
Promise. The state change of all() is related to the state of all incoming promise instance objects
All States become resolved, and the final state will become resolved
As long as one becomes rejected, the final state becomes rejected
See code:
// Encapsulate a delay function: const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return 'p1'; // The Promise object that returns the success status by default }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return 'p2'; // The Promise object that returns the success status by default }); const p = Promise.all([p1, p2]); p.then( data => { console.log(data); }, err => { console.log(err); } );
The execution result in the above code is: p1 is completed (one second later), p2 is completed (2) ["p1", "p2"] (two seconds later)
The final status of this code is resolved
Look at the following code:
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return Promise.reject('reason'); }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return 'p2'; }); const p = Promise.all([p1, p2]); p.then( data => { console.log(data); }, err => { console.log(err); } );
The result of this code is: p1 completes reason (Note: print in one second) p2 completes reason (Note: print in two seconds)
There is rejected in this code, so the final state is rejected. You may wonder why reason appears after p1 is completed. You can understand this: because the system detects rejected somewhere, it directly determines promise The state of all is rejected, so the second callback function of the then method behind p is directly executed, so the reason is printed. And because the rejected state is detected in p1, the reason appears after p1 is completed.
You can check whether the handwriting is understood through the following examples:
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return 'p1'; }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return Promise.reject('reason'); }); const p = Promise.all([p1, p2]); p.then( data => { console.log(data); }, err => { console.log(err); } );
The result here is: p1 is completed (Note: print out in one second) p2 is completed (Note: print out in two seconds)
Promise.race() and promise allSettled():
First of all, we can simply understand these two methods.
1,Promise.race():
Promise. The state of race () depends on the promise instance object completed first. If the first one is completed successfully, the final one will succeed; If the first one fails, the final one fails.
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return 'p1'; }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return 'p2'; }); const racePromise = Promise.race([p1, p2]); racePromise.then( data => { console.log(data); }, err => { console.log(err); } );
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return 'p1'; }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return Promise.reject('reason'); }); const racePromise = Promise.race([p1, p2]); racePromise.then( data => { console.log(data); }, err => { console.log(err); } );
Here are two examples for you to verify and learn by yourself. I won't go into detail here. You can see it at a glance as soon as you run it on your compiler.
2,Promise.allSettled():
Promise. The state of allsettled() has nothing to do with the incoming promise state. The then method behind it will always execute the successful callback function, and it will only faithfully record the performance of each promise. See code:
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return 'p1'; }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return Promise.reject('reason'); }); const allSettledPromise = Promise.allSettled([p1, p2]); allSettledPromise.then(data => { console.log('succ', data); });
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return Promise.reject('reason'); }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return Promise.reject('reason'); }); const allSettledPromise = Promise.allSettled([p1, p2]); allSettledPromise.then(data => { console.log('succ', data); });
You can demonstrate the above two examples by yourself, and you will understand the results.
Precautions for Promise:
1. Code after the resolve or reject function is executed:
It is recommended to add return when calling the resolve or reject function and do not execute the code behind them.
For example:
new Promise((resolve, reject) => { // // return resolve(123); return reject('reason'); });
Although the code behind the resolve or reject function can still be executed. For example:
new Promise((resolve, reject) => { // // return resolve(123); return reject('reason'); console.log('hi'); }); // hi
But this is not recommended.
2,Promise. Parameter problem of all / race / allsettled:
If the parameter is not an array of Promise objects, the system will convert the array elements that are not Promise objects into an array of Promise objects by default.
Promise.all([1, 2, 3]).then(datas => { console.log(datas); }); // Equivalent to Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3) ]).then(datas => { console.log(datas); });
Parameters are not just arrays. Any traversable can be used as parameters:
Such as: native traversable: array, string, Set, Map, NodeList, arguments
And non-native traversable (via Iterate)
Take chestnuts for example:
// Set as parameter Promise.all(new Set([1, 2, 3])).then(datas => { console.log(datas); });
3,Promise. Error handling of all / race / allsettled:
Separate treatment:
// First case: const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return Promise.reject('reason'); }).catch(err => { console.log('p1', err); }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return Promise.reject('reason'); }).catch(err => { console.log('p2', err); }); const allPromise = Promise.all([p1, p2]); allPromise.then(datas => { console.log(datas); });
Unified processing:
// The second case: const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; const p1 = delay(1000).then(() => { console.log('p1 It's done'); return Promise.reject('reason'); }); const p2 = delay(2000).then(() => { console.log('p2 It's done'); return Promise.reject('reason'); }); const allPromise = Promise.all([p1, p2]); allPromise.then(datas => { console.log(datas); }).catch(err => console.log(err));
Errors can be handled individually or in a unified manner Once processed, it will not be processed again elsewhere (the second case above)