You will learn from this article
- What is a promise
-
An internal implementation of Promise
- Resolve instance property
- Reject instance property
- Then method
- Multiple invocations of the then method
- A chained call to a then
- Error trapping
try{}catch(e){}
- Then optional parameter
- The implementation of static method all
- The implementation of the static resolve method
- The implementation of the instance method finally
-
The implementation of the instance method catch
What is a promise
Step analysis
/** * 1.Promise is a fulfilment of a class, and the parameter is a callback function, which will be executed immediately. * 2. * Pending -> rejected * 3. Fulfill () Pending -> fulfilled *. This can be very depressing Reject () pending -> rejected * 4. Then: reject() pending -> rejected * 4. Then: reject() pending -> rejected * 4. * Then methods are defined in the prototype object * 5. The successful callback function of the THEN takes an argument that represents the value after success. */ new Promise((resolve,reject)=>{resolve(" succeed ") // reject(" fail ")})
implementation
Implement the most basic function
Declares a MyPromise class, receives an executor in the constructor, and executes the executor immediately
Const PENDING = 'PENDING '; // Waiting for a const FULFILLED = 'FULFILLED '; // Succeed const REJECTED = 'REJECTED '; Class MyPromise {constructor(executor) {// The constructor accepts two arguments. Resolve and reject // The executor immediately executes executor(this.resolve, this.reject); } status = pending; status = pending; status = pending; status = pending; status = pending; status = pending; }
When executing the executor, you pass two arguments, resolve and reject.
- Both methods are called directly when executed in the body of the executor function
resolve(); reject()
- If we execute a function directly, this inside the function body will point to window.
- So use the arrow function when defining the resolve and reject methods to avoid the problem of this pointing to the Promise instance.
- In the body of the executor function, resolve and reject are used to change the state of the Promise, and after the change, it cannot be changed again
Class MyPromise {// constructor executor... Resolve = () => {// When state is not pending, return. if (this.status ! == PENDING) return; this.status = FULFILLED; } reject = () => {// When the state is not pending, return. if (this.status ! == PENDING) return; this.status = REJECTED; }}
Resolve (‘ data after success ‘) reject(‘ reason for failure ‘). So take the arguments in the resolve and reject and store them in the instance properties
Class MyPromise {// constructor executor... // cause = undefined = resolve = value => {// cause = undefined = resolve = value => {// cause = undefined = resolve = value =>; The return. if (this.status ! == PENDING) return; this.status = FULFILLED; // Save the successful value this.value = value; } reject = reason => {// no pending status, return. if (this.status ! == PENDING) return; this.status = REJECTED; This. reason = reason; this.reason = reason; }}
After calling Promise(), a Promise instance is returned with a Then method for handling successful or failed callbacks that end within a function
then
There are two arguments, one of which is a successful callbacksuccessCallback
, one is a failed callbackfailCallback
- In the call
successCallback
The successful data/value needs to be passed in- In the call
failCallback
“, you need to pass on the reason for the error- The value of success and the reason for failure have been used in the defined variables
value
和reason
I saved it.
To call a successful or failed callback, we need to look at the state of the Promise:
If it is Fulfilled the callback is successful; If it is a callback to a Rejected call that failed;
class MyPromise{ ... then(successCallback, failCallback) { if (this.status === FULFILLED) { successCallback(this.value); } else if (this.status === REJECTED) { failCallback(this.reason); }}}
Adding asynchronous logic
If you use a Promise, put resolve or reject in the asynchronous logic.
Resolve (() = resolve(' success ')}, 2000)
In this case, if you use “then”, then will determine the Promise status, while the status is still padding.
Because the status of the Promise is changed by calling resolve/reject. When you delay the call to resolve/reject, you delay the update of the state.
The then method only determines the status of success and failure, and does not determine the status of wait (also the asynchronous state).
then(successCallback, failCallback) { if (this.status === FULFILLED) { successCallback(this.value); } else if (this.status === REJECTED) { failCallback(this.reason); }}
So here’s what we need to do: if the Promise is in a pending wait state when we call Then, we need to store successful and failed callbacks passed in so that we can delay the end of the call.
class MyPromise { ... // SuccessCallback = undefined; // Failed callback failCallback = undefined; . then(successCallback, failCallback) { if (this.status === FULFILLED) { successCallback(this.value); } else if (this.status === REJECTED) { failCallback(this.reason); } else {// Wait for // Save successful and failed callbacks this.successCallback = successCallback; this.failCallback = failCallback; }}}
Then, at the end of the asynchronous logic, a call is made to resolve or reject, at which point the resolve or reject method in the Promise can be used to determine if there is a corresponding callback and, if so, execute it
resolve = value => { ... This.successCallback (this.value)} reject = reason => {... This.failcallback (this.reason); this.failcallback (this.reason); this.failcallback (this.reason); }
Implement a Then method to add multiple handlers multiple times
- Each Promise object’s then method can be called multiple times,
- When a then method is called, the callback function inside each then method will be called
- If you call the THEN method multiple times, you should store all of the callbacks in the THEN method and execute them in turn when the Promise state changes
-
In order to store callbacks in multiple Then’s, you need to change the successCallback and failCallback properties to arrays
// SuccessCallback = undefined; successCallback = []; // Failed callback // FailCallback = undefined; failCallback = []; then() { ... // Save successful and failed callbacks // this.successcallback = successCallback; // this.failCallback = failCallback; this.successCallback.push(successCallback); this.failCallback.push(failCallback); . }
These callbacks are then called in turn when the Promise state is updated
resolve = value => { ... // If a successful callback exists, execute it // this.successCallback && this.successCallback(this.value); While (enclosing successCallback. Length) {/ / popup first callback function, and perform the enclosing successCallback. The shift () (value) this.; } } reject = reason => { ... // If a failure callback exists, execute it // this.failCallback && this.failCallback(this.reason); While (this.failCallback.length) {// The first callback function pops up and executes this.failCallback.shift()(this.reason); }}
use
promise.then(value => { console.log(1); console.log(value); }); promise.then(value => { console.log(2); console.log(value); }); promise.then(value => { console.log(3); console.log(value); });
The results of
1 success 2 success 3 success
A chained invocation of a then method
- Promise’s then methods can be chained
- The value returned by the callback in each then method is the value returned by the callback in the previous then method
// test.js promise .then(value => { console.log(value); return 100; }).then(value = 100 console.log(value);}).then(value = 100 console.log(value); / / 100});
- Implement chained calls to then methods
Each Then method returns a Promise object
then(successCallback, FailCallback) {let promise2 = new MyPromise(() => {if (this.status === = FULFILLED) { successCallback(this.value); } else if (this.status === REJECTED) { failCallback(this.reason); } else {// Wait for // Save successful and failed callbacks // this.successCallback = successCallback; // this.failCallback = failCallback; this.successCallback.push(successCallback); this.failCallback.push(failCallback); }}); // return promise2; }
- The return value of the previous THEN method callback is passed to the next THEN method callback
- In order for the next Then to receive the previous Then, the previous Then returns a ProMMISE object
-
Gets the return value of the callback function
/ / success callback then (successCallback, failCallback) {... Fulfilling () = new MyPromise(() =>) {if (this.status === = Fulfilling) {let X = successCallback(this.value); }... }); return promise2 }
Pass the x to the next then. Anyway, the next one is a then for a user, but instead of being a user, then is a then for a user.
If promise2 is called, then promise2 will then be executed and the passing x will be passed to the next then via resolve(x)
/ / success callback then (successCallback, failCallback) {/ / as long as you call the resolve method, Let promise2 = new MyPromise((resolve, reject) => {let x = successCallback(this.value); resolve(x); })}
The judgment of the return value from the chain call of the then method
- If the value returned from the previous then method callback is a normal value, resolve;
- If the last then method callback returns a Promise object, you need to determine the result (state) of the Promise object and decide whether to use resolve or reject based on that state
/ / success callback then (successCallback, failCallback) {let promise2 = new MyPromise ((resolve, reject) => { let x = successCallback(this.value); // If it is a Promise object, call resolve directly. If it is a Promise object, look at the result returned by the Promise object. // Resolve (x, reject); // Resolve (x, reject, reject); }) } function resolveRromise(x, resolve, Reject) {// use instanceof to determine if x is an instanceof MyPromise if (x instanceof MyPromise) {// call the then method to see the return value of x, // if this is successful, (promise2) (first argument method then is called, then is called) (second argument method then is called) (second argument method then is called) If (value => reject(value), reason => reject(reason)) x.then(value => reject(reason)); } else { resolve(x) } }
test
function other (){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log("other") },2000) }) } Promise. Then (value=>{console.log(value) return other() // return other()). Then (value=>{console.log(value) // output other})
The then method chain call recognizes the Promise object as returning
If the callback function of the then method returns itself (the Promise object), the Promise will be called in a loop. This is not allowed: Chaining cycle detected for promise #
var promise1 = new Promise((resolve, reject) => { resolve(100); }); var promise2 = promise1.then(value => { console.log(value); // Promise2 is now a traffic controller. })
Is promise2 the value of the current Then promise2 object the same as the value of x that it returns to the next Promise object in the next Then? If so, it is a reversion.
. ResolvePromise (promise2, promise2, promise2) then(promise2, promise2, promise2, promise2){ }... function resolvePromise(promise2, x, resolve, Reject) {// Reject if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>')} // use instanceof to determine if x is a MyPromise object if (x instanceof MyPromise) {// call the then method to see the return value of x, // If it is successful, call resolve; // x.then(value => resolve(value), reason => reject(reason)) x.then(resolve, reject); } else { resolve(x) } }
Promise2 is new MyPromise((resolve, reject) => {… } is now a user who is supposed to get promise2 in the middle of its execution.
The solution is to switch the code that fetches a callback and compares promise2 to x to execute asynchronously. It will execute after all the synchronization code of the then method has finished executing, in order to get promise2
// Put promise2 setTimeout(() => {let X = successCallback(this.value); // Put promise2 setTimeout() = promise2 ()); // If it is a Promise object, call resolve directly. If it is a Promise object, look at the result returned by the Promise object. // resolve(x); // resolve(x); resolveRromise(promise2, x, resolve, reject); }, 0);
Catch errors and then chain calls to other status code additions
- Catch the error of the actuator
Use a try/catch to catch exceptions while executing the executor
-
Gets e.message when the passed executor is an error and is not a normal executor
class MyPromise { constructor(executor) { try { executor(this.resolve, this.reject); } catch (err) { this.reject(err); }}}
- Catch then method callback function execution exceptions
- If an exception occurs within the callback function of the then method, or within the callback function of the then method
throw new Error
-
Reject the error handling callback function that is passed to the next THEN method
Let x = successCallback(this.value); let x = successCallback(this.value); // If it is a Promise object, call resolve directly. If it is a Promise object, look at the result returned by the Promise object. // resolve(x); // resolve(x); resolveRromise(promise2, x, resolve, reject); } catch (err) {// pass the exception to the next then method's error handling callback, reject(err); }
- Handle catch chain calls
We dealt with the chained call to resolve case earlier. Reject is processed in the same way.
. else if (this.status === REJECTED) { // failCallback(this.reason); // Change the code to execute asynchronously, Promise2 setTimeout(() => {try {let x = failCallback(this.reason); // If it is a Promise object, call resolve directly. If it is a Promise object, look at the result returned by the Promise object. // resolve(x); // resolve(x); resolveRromise(promise2, x, resolve, reject); } catch (err) {// pass the exception to the next then method's error handling callback, reject(err); }}, 0); }...
!!!!!!!!! Note:
If a normal value (such as 10000) is returned in the error handling callback, it goes to the success handling callback of the next THEN method.
If the return is a failure, it goes into the error handling callback function of the next THEN
Const Promise = new MyPromise((resolve, reject) => {reject(' reject ')); }); promise .then(value => { console.log(value); return 100; }, reason => { console.log(reason); Return 10000; // return 10000; // return 10000; }) .then(value => { console.log(value); // => 10000 }, reason => { console.log(reason); });
- Handles chain calls to asynchronous logic and catches run exceptions
. Else {// wait for // Save successful and failed callbacks // this.successCallback = successCallback; // this.failCallback = failCallback; // this.successCallback.push(successCallback); // this.failCallback.push(failCallback); // save a function, This function implementation success/failure callback enclosing successCallback. Push ((() = > {setTimeout () = > {try {/ / save the return value of a callback let x = success successCallback(this.value); // If it is a Promise object, call resolve directly. If it is a Promise object, look at the result returned by the Promise object. // resolve(x); // resolve(x); resolveRromise(promise2, x, resolve, reject); } catch (err) {// pass the exception to the next then method's error handling callback, reject(err); }}, 0); }); This.failCallback. push(() => {setTimeout(() => {try {let x = failCallback(this.reason); // If it is a Promise object, call resolve directly. If it is a Promise object, look at the result returned by the Promise object. // resolve(x); // resolve(x); resolveRromise(promise2, x, resolve, reject); } catch (err) {// pass the exception to the next then method's error handling callback, reject(err); }}, 0); }); }
After that, you don’t need to pass a value when you go back to the function.
. this.successCallback.shift()(); . this.failCallback.shift()();
Make the THEN method an optional parameter
The Promise’s Then method takes optional arguments. If you call a Then method without passing arguments, how does the Promise flow?
const promise = new MyPromise((resolve, reject) => {
resolve(100);
});
promies
.then()
.then()
.then(value => console.log(value)) // 100
This is the case when a then method passes no arguments
Promise. Then (value => value) // Receive the parameter and return the parameter directly
In this case, the Promise state is passed to the next Then method
Then (successCallback, failCallback) {// Check if there is a passing parameter in successCallback = successCallback? successCallback : value => value; failCallback = failCallback ? failCallback : reason => { throw reason }; . }
Promise. All methods
-
The Promise.all method is used to execute asynchronous tasks sequentially and to get sequential results
const p1 = function() { return Promise(resolve => { setTimeout(() => { resolve('p1'); }, 2000) }) } const p2 = function() { return new Promise(resolve => { resolve('p2'); }) } Promise.all(['a', 'b', p1(), p2(), 'c']).then(results => { // ['a', 'b', 'p1', 'p2', 'c'] })
2S output [‘a’, ‘b’, ‘p1’, ‘p2’, ‘c’],
- The promise.all method takes an array, executes it internally in order of the elements of the array, and when it’s all done, returns the result together, which is also an array corresponding to the array that was passed in.
- If one of them fails. The result returned is a failure.
Static static all(array) {const result = []; static static all(array) {const result = []; Let index = 0; let index = 0; Return new MyPromise((resolve, reject) => {function addRes(I, reject) =>; value) { result[i] = value; +1 index++; If (index === Array.length) resolve(result); if (index === Array.length); } // iterate through the array and determine if each element is a normal value or a Promise object. If it is a Promise object, drop the element directly into the result set. If it is a Promise object, fetch its return value and drop it into the result set for (let I = 0; i < array.length; i++) { let current = array[i]; If (current instanceof myPromise) {current. Then (value => addRes(I, value), reason => reject(reason)) } else { addRes(i, current); }}})}
Promise. The resolve method
- The promise.resolve method converts a given value to a Promise object.
-
The promise.resolve object returns a Promise object that wraps the given value.
Promise.resolve(10).then(value => console.log(value)); / / 10
- If a Promise object is passed in, it returns the Promise object intact
function p1 () { return new Promise((resolve, reject) => { resolve(100) }) } Promise.resolve(p1()).then(value => console.log(value)); / / 100
If (value instanceof myPromise) return value; if (value instanceof myPromise) return value; Return new MyPromise(resolve => resolve(value)); }
finally
- The finally callback is called whether the Promise’s state succeeds or fails
- The nonclass method receives a callback function. The finally method’s callback is always executed once, whether the Promise object succeeds or fails
- You can chain call then to get the result returned by the current Promise object
-
A return ina finally method callback can return a Promise object, and a subsequent then method callback should wait for the Promise to finish executing before proceeding
Finally (callback){return this.then(value=>){return value (); Callback () {return ();} return () {return (); })}
Since callback can also return Promise, use resolve to resolve
Note that the value and reason returned is the value of the promise in the following example, not the value returned by the promise in the callback
finally(callback){ return this.then(value=>{ return MyPromise.resolve(callback()).then(()=>value) Return myPromise.resolve (callback()).then(()=>{throw reason}).return myPromise.resolve (); // Note the reason})}
call
Const Promise = new MyPromise((resolve, reject) => {reject(' reject ')); }); Const p1 = function () {return myPromise (resolve) => {setTimeout(() => {resolve(' 2S '); }, 2000); }) } promise.finally(() => { console.log('finally'); return p1(); // return Promise object}). Then (value => {console.log(value); }, reason => { console.log(reason); })
The finally failed
Catch method
- The catch method is used to handle cases where the current Promise object’s final state fails.
- Using it, we can avoid passing failed callbacks in the Then method.
All you need to do is call the then method inside the catch method, passing the success callback of the then method to undefined, and passing the failure callback to a callback function
catch(failCallback) {
return this.then(undefined, failCallback);
}
test
promise.finally(() => { console.log('finally'); return p1(); // return Promise object}). Then (value => {console.log(value); }).catch(reason => { console.log('catch', reason) })
The finally failed to catch