Promise constructs and state declarations

1. Promise is used with the new keyword, so it should be implemented with a constructor or class

 class HSPromise {    
     constructor() {
         
      }  
 }
Copy the code

2. Define the three state types

 const PENDING = 'pending'
 const FULFILLED = 'fulfilled' 
 const REJECTED = 'rejected'
Copy the code

3. Set the initial status

Class HSPromise {constructor() {// initial state is pending this.status = pending; this.value = null; this.reason = null; }}Copy the code

Resolve and reject methods

1. According to the specification, these two methods will change the status, from pending to fulfilled/rejected.

2. Note that the input parameters of the two functions are value and Reason, respectively

Class HSPromise {constructor() {// initial state is pending this.status = pending; this.value = null; this.reason = null; } resolve(value) { if (this.status === PENDING) { this.status = FULFILLED; this.value = value; } } reject(reason) { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; }}}Copy the code

Promsie to join

1. The input parameter is a function that takes resolve and reject.

2. Note that this function is executed when the promise is initialized, and any errors are thrown via reject

Class HSPromise {constructor(fn) {// initial state is pending this.status = pending; this.value = null; this.reason = null; try { fn(this.resolve.bind(this), this.reject.bind(this)); } catch (e) { this.reject(e); } } resolve(value) { if (this.status === PENDING) { this.status = FULFILLED; this.value = value; } } reject(reason) { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; }}}Copy the code

The implementation of the then method

1. This parameter is fulfilled and onRejected

then(onFulfilled, onRejected) {}
Copy the code

2. Check and process parameters. If the parameter is not function, ignore it. This omission refers to returning value or reason as is

  isFunction(param) {   
     return typeof param === 'function';   
   }  

  then(onFulfilled, onRejected) {     
     const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled 
        : (value) => {      
            return value;      
          }      
      const rejectedFn = this.isFunction(onRejected) ? onRejected 
        : (reason) => {   
            throw reason    
          }; 
   }        
Copy the code

3. Call different functions based on the current promise state

then(onFulfilled, onRejected) { const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value; } const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; switch (this.status) { case FULFILLED: { fulFilledFn(this.value); break; } case REJECTED: { rejectedFn(this.reason); break; }}}Copy the code

4. In this way, the then function is executed the instant it is called. What if status has not become fulfilled or rejected? It will probably be pending.

Get all the callbacks first, and then execute them at some point. Create two new arrays to store the success and failure callbacks. When we call THEN, we store the Promise in the array if it is still pending.

then(onFulfilled, onRejected) { const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value; } const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; switch (this.status) { case FULFILLED: { fulFilledFn(this.value); break; } case REJECTED: { rejectedFn(this.reason); break; } case PENDING: { this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled); this.REJECTED_CALLBACK_LIST.push(realOnRejected); break; }}}Copy the code

5. Perform all callbacks when status changes; The getters and setters of ES6 are used here, which is more semantic.

When status changes, do something. (You can also do it sequentially. After you assign status, add a forEach line below to do something.)

get status(){ return this._status; } set status(newStatus) { switch (newStatus) { case FULFILLED: { this.FULFILLED_CALLBACK_LIST.forEach(callback => { callback(this.value); }); break; } case REJECTED: { this.REJECTED_CALLBACK_LIST.forEach(callback => { callback(this.reason); }); break; }}}Copy the code

Then return value

This will be fulfilled fulfilled. If onFulfilled or onRejected throws an exception e, promise2 must refuse to execute and return rejected e. (You need to catch the code manually, reject the error.)

then(onFulfilled, onRejected) { const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => { return value; } const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => { throw reason; }; const fulFilledFnWithCatch = (resolve, reject) => { try { fulFilledFn(this.value); } catch (e) { reject(e) } }; const rejectedFnWithCatch = (resolve, reject) => { try { rejectedFn(this.reason); } catch (e) { reject(e); } } switch (this.status) { case FULFILLED: { return new HSPromise(fulFilledFnWithCatch); } case REJECTED: { return new HSPromise(rejectedFnWithCatch); } case PENDING: { return new HSPromise((resolve, reject) => { this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWithCatch(resolve, reject)); this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWithCatch(resolve, reject)); })}}}Copy the code

2. If onFulfilled is not the function and PromisE1 is successfully executed, Promise2 must be successfully executed and return the same value.

 const fulFilledFnWithCatch = (resolve, reject) => {    
      try {        
           fulFilledFn(this.value);           
           resolve(this.value);          
       } catch (e) {    
           reject(e)    
       }      
  }
Copy the code

If onRejected is not a function and Promise1 rejects it, promise2 must reject it and return the same reason.

If promise1 onRejected is successfully executed, promise2 should be resolved

const rejectedFnWithCatch = (resolve, reject) => { try { rejectedFn(this.reason); if (this.isFunction(onRejected)) { resolve(); } } catch (e) { reject(e); }}Copy the code

If onFulfilled or onRejected returns a value x, run the resolvePromise method

then(onFulfilled, onRejected) {  
      const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled 
             : (value) => {           
                 return value;       
               }       
      const rejectedFn = this.isFunction(onRejected) ? onRejected 
             : (reason) => {         
                 throw reason;     
               };     
      const fulFilledFnWithCatch = (resolve, reject) => {       
             try {         
                 if (!this.isFunction(onFulfilled)) {      
                     resolve(this.value);            
                  } else {             
                     const x = fulFilledFn(this.value);   
                     this.resolvePromise(newPromise, x, resolve, reject);              
                    }     
             } catch (e) {           
                reject(e)         
             }      
       };    
      const rejectedFnWithCatch = (resolve, reject) => {        
             try {        
                if (!this.isFunction(onRejected)) {          
                     reject(this.reason);           
                } else {                 
                     const x = rejectedFn(this.reason);       
                     this.resolvePromise(newPromise, x, resolve, reject);            
                   }   
             } catch (e) {          
                reject(e);      
             }     
      }     
      switch (this.status) {   
             case FULFILLED: {       
                 const newPromise = new HSPromise((resolve, reject) =>                     
                   fulFilledFnWithCatch(resolve, reject, newPromise))            
                 return newPromise       
             }    
             case REJECTED: {  
                 const newPromise = new HSPromise((resolve, reject) =>                     
                   rejectedFnWithCatch(resolve, reject, newPromise))      
                 return newPromise             
            }       
             case PENDING: {            
                 const newPromise = new HSPromise((resolve, reject) => {                           
                  this.FULFILLED_CALLBACK_LIST.push(() => 
                       fulFilledFnWithCatch(resolve, reject, newPromise));
                  this.REJECTED_CALLBACK_LIST.push(() => 
                      rejectedFnWithCatch(resolve, reject, newPromise));            
                  });                 
                 return newPromise;
             }     
         }   
 } 
Copy the code

ResolvePromise method

ResolvePromise (newPromise, x, resolve, reject) {// if newPromise and x point to the same object, Reject (newPromise === x) {reject(new TypeError('The promise and The return value are the same')); } if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) {if (x instanceof MPromise) { X. tet ((y) => {resolvePromise(newPromise, y, resolve, reject); }, reject); } else if (typeof x = = = 'object' | | this. IsFunction (x)) {/ / / / if x is an object or function of the pit is the time to run test found that, if x is null, Resolve (x === null) {return resolve(x); } let then = null; Try {// assign x.hen to then then = x.hen; } catch (error) {// Promise return reject(error), reject(error), reject(error), reject(error); } if (this.isfunction (then)) {let called = false; // The first parameter is resolvePromise, the second parameter is rejectPromise, and the second parameter is rejectPromise. Try {then. Call (x, // if the resolvePromise is called with the value y, Run resolvePromise (y) => {// If both resolvePromise and rejectPromise are called, // or the same argument is called multiple times, // This requires a variable called if (called) return; called = true; resolvePromise(promise, y, resolve, reject); }, // rejectPromise (r) => {if (called) return;}, // rejectPromise (r) => {if (called) return; called = true; reject(r); }); } catch (error) {// If the then method throws an exception e: // If either resolvePromise or rejectPromise has been called, ignore it if (called) return; // Reject (error); }} else {// If then is not a function, promise resolve(x); }} else {// Promise resolve(x) if x is not an object or function; }}Copy the code

This is very depressing and onRejected are micro tasks

Execute functions wrapped in queueMicrotask

const fulFilledFnWithCatch = (resolve, reject) => {  
   queueMicrotask(() => {     
       try {         
            if (!this.isFunction(onFulfilled)) {      
                resolve(this.value);            
            } else {             
                const x = fulFilledFn(this.value);   
                this.resolvePromise(newPromise, x, resolve, reject);              
            }     
       } catch (e) {           
            reject(e)         
       }      
   }) }    
const rejectedFnWithCatch = (resolve, reject) => {  
   queueMicrotask(() => {     
       try {        
            if (!this.isFunction(onRejected)) {          
                reject(this.reason);           
            } else {                 
                const x = rejectedFn(this.reason);       
                this.resolvePromise(newPromise, x, resolve, reject);            
            }   
       } catch (e) {          
           reject(e);      
       }    
   }) 
}     
Copy the code

Catch method

  catch (onRejected) {  
      return this.then(null, onRejected);   
   }
Copy the code

Promise.resolve

This will be fulfilled fulfilled. If the parameter of promise. resolve is not an object with the then method (also called thenable), a new Promise object will be returned with the state fulfilled.

 

static resolve(param) { if (param instanceof HSPromise) { return param; } return new MyPromise(function (resolve) { resolve(param); }); }Copy the code

Promise.reject

1. Return a new Promise instance whose status is Rejected. The reason argument to the promise. reject method is passed to the instance callback function.

static reject(reason) {     
   return new MPromise((resolve, reject) => {      
      reject(reason);      
    });   
 }
Copy the code

Promise.race

const p = Promise.race([p1, p2, p3])

1. This method is to wrap multiple Promise instances into a new Promise instance. Whenever one instance of P1, P2, or P3 changes state first, the state of P changes accordingly. The return value of the Promise instance that changed first is passed to the p callback function.

static race(promiseList) { return new MPromise((resolve, reject) => { const length = promiseList.length; if (length === 0) { return resolve(); } else { for (let i = 0; i < length; i++) { HSPromise.resolve(promiseList[i]).then( (value) => { return resolve(value); }, (reason) => { return reject(reason); }); }}})}Copy the code