Promise specification

promise states

A PROMISE has three states: Pending Ready Resolve Successful Reject Failed

1 .pending

This state can be fulfilled or rejected before a promise is fulfilled or rejected. This state can be fulfilled or rejected

  1. fulfilled

The final immutable state is implemented by calling resolve. The resolve callback must have a value.

3.rejected

The final immutable state is implemented by calling Reject. The callback in Reject must have a value of Reason (either a callback with arguments in catch or a callback with arguments in the second method of then)

then

A promise should provide a THEN method that accesses the final result, either value or Reason.

promise.then(onFulfilled,onRejected)
Copy the code

1. Parameter requirements

Both arguments in then must be of function type. If they are not of function type, the program ignores that the default parameter is of function type and returns the corresponding value or reason

  1. onFulfilled

When the promise becomes a big pity, the ondepressing parameter should be called as value. Before the pity, the call cannot be performed but once

  1. onRejected

When the promise changes to onRejected, the onRejected parameter should be called as reason. Before rejected, the call cannot be made and can only be performed once

This is a big onFulfilled and onRejected

With queueMicrotask (callback) implementation

5 The then method can be called multiple times using array memory onFulfilled and onRejected

promise.then(fn)
promise.then(fn)
promise.then(fn)
promise.then(fn)
promise.then(fn)
Copy the code

6. Then should return a Promise object for the chain call


promise2 = promise1.then(onFulfilled, onRejected);
Copy the code

The onFulfilled or onRejected executes an exception. We call resolvePromise(). If onFulfilled or onRejected executes an exception, we throw it through reject This is a pity reson-> fulfilled function. This is a pity reson-> fulfilled function

This is a big promise, which is a pity or onRejected callback function. This is a big promise, which is a pity or onRejected callback function. If x===promise2, reject(new Error)

7.2 If x is a promise, we need to continue to call x’s then method and pass the returned value into the resolvePromise until x is a basic type

Let then = x.teng. Let then = x.teng. If x. Teng fails, Call (x, resolvePromiseFn, rejectPromise) then call(x, resolvePromiseFn, rejectPromise) y, resolve, reject); The input argument to the rejectPromise is R, reject(r). If both resolvePromise and rejectPromise are invoked, the first invocation takes precedence and subsequent invocations are ignored. If a call to THEN throws an exception e, reject(error) if resolvePromise or rejectPromise has already been called

Resolve (x) resolve(x)

resolvePromise(promise2, x, resolve, reject)
Copy the code

implementation

/ / / written promise
// Define the three states in promise
const   PENDING='pending'
const   FULFILLED= 'fulfilled'
const   REJECTED='rejected'
// The point of resetting a status is that we execute the array method when the status changes
The reject and resolve functions perform only one behavior, following the rule of function singleness

class JKQPromise{
    FULFILLED_CALLBACK_LIST=[]
    REJECTED_CALLBACK_LIST=[]
    _status=PENDING
    constructor(fn){
        // Initial default value
        this.status=PENDING
        this.value=null
        this.reason=null
      // Execute fn's method to specify this
     try{
        fn(this.resolve.bind(this),this.reject.bind(this))}catch(e){
      this.reject(e)
     }
    }

    get status() {return this._status  // If you use this.status directly, an infinite loop will be created
    }
    set status(newStatus) {this._status=newStatus
        // We execute the methods in the callback array when the state changes
        switch(this.status){
            case  FULFILLED:
                this.FULFILLED_CALLBACK_LIST.forEach(callback= >{callback(this.value)})
            break;
            case REJECTED:
                this.REJECTED_CALLBACK_LIST.forEach(callback= >{callback(this.reason)})
                break; }}// Change the state in the promise
    //resolve
    resolve(value){
        console.log(value,'3331ss')
        if(this.status===PENDING){
          this.status=FULFILLED
          this.value=value
        }

    }
    //reject
    reject(reason){
        if(this.status===PENDING){
            this.status=REJECTED
            this.reason=reason
          }

    }
    //the then method has two successful and failed callbacks
    then(onFulfilled,OnRejected){
        // The method type that determines the callback should be ignored if it is not a function
     let  realFulfilled=this.isFunction(onFulfilled)? onFulfilled:value= >value
     let realRejected=this.isFunction(OnRejected)? OnRejected:reason= >reason
     // The then method still returns a Promise object (new)
     let promise2 =  new JKQPromise((resolve,reject) = >{
          // Place incoming callback functions in an array so that they can be executed uniformly when the state changes
   
     // If the previous promise fails, the next THEN cannot be obtained
     let fulfilledMicrotask=() = >{
       queueMicrotask(() = >{
        try{
            //resolve the return value after execution
            let x= realFulfilled(this.value)
            this.resolvePromise(promise2,x,resolve,reject)
        }catch(e){
        // If the error throws an error
           reject(e)
        }
       })
      
    }
    let rejectedMicrotask=() = >{
        queueMicrotask(() = >{
            try{
                const x = realRejected(this.reason)
                this.resolvePromise(promise2,x,resolve,reject)
            }catch(e){
                reject(e)
            }
        })
      
       
    }
      switch(this.status){
        case  FULFILLED:
            fulfilledMicrotask()
        break;
        case REJECTED:
            rejectedMicrotask()
        
          break;
          case PENDING:
              // Add the successful or failed callback function to the corresponding callback array
              this.FULFILLED_CALLBACK_LIST.push(onFulfilled)
              this.REJECTED_CALLBACK_LIST.push(OnRejected)
              break}})// Return the Promise object to implement the chain call
    return promise2
    }
   // Determine and handle the callback x
     resolvePromise(promise2,x,resolve,reject){
    if(promise2===x){
    /// return an error if the instance and the returned object are the same thing
      return reject(new Error('the same object'))}if(x instanceof JKQPromise){
         console.log(x)
        // If it is an instance of promise, the call is repeated and the value retrieved from the call is parsed
        queueMicrotask(() = >{
            x.then((y) = >{
                /// Get the last basic type of data through a loop call (see the test for details) for the next chain call
                this.resolvePromise(promise2,y,resolve,reject)
            },reject)

        })

    }else if(typeof x === 'object' || this.isFunction(x)){
          / / null objects
          if(x === null) {return  resolve(x)
          }
          let then  = null
          try {
            // assign x. teng to then
            then = x.then;
        } catch (error) {
            // If an error e is thrown when taking the value x. teng, reject a promise based on e
            return reject(error);
        }
       If then exists in an object or function and then is a function
        if(this.isFunction(then)){
        // This command can be executed only once
           let  called=false
           try{
             then.call(x,(y) = >{
                 if(called)return
                 called=true
                 / / success
                 this.resolvePromise(promise2,y,resolve,reject)
             },(r) = >{
             / / fail
                 if(called)return
                 called=true
                 reject(r)
             })
           }catch(e){
              if(called) return
              // Execute error reject
              reject(e)
           }

        }else{
            // Execute resolve if it is not a function
            resolve(x)
        }
    
      }else{
          // Execute resovle directly
          resolve(x)
      }

    }

    
    
     catch(OnRejected){
         // Returns a call to THEN
         return this.then(null,OnRejected)

     }
   

    
    isFunction(params){
        return typeof params ==='function'
    }

// A direct call to resolve
  static resolve(value){
      if(value instanceof JKQPromise){
         // If value is an instance of promise, return the implementation chain call
         return value
      }else{
          new JKQPromise((resolve,reject) = >{
              resolve(value)
          })
      }
  }

  static reject(reason) {
    return new MPromise((resolve, reject) = > {
        reject(reason);
    });
    
    
    
  static all(arrays){
    return new MPromise((resolve,reject) = >{
        if(!Array.isArray(arrays)){
            throw new Error('Not an array')}let length =arrays.length
        let resolveArray=[]
        for(let i =0; i< length; i++){ arrays[i].then(data= >{
                resolveArray.push(data)
                if(length==resolveArray.length){
                    // Resove can be obtained by then
                    resolve(resolveArray)
                }
            },reject)
            
        }
    })
       

    }
}
}

Copy the code

1. The then method returns a new Promise whose initial state is pending

2. When the onFulfilled in the first promise is not a function, the value of the resolve or the default will be passed to the newly created promise for later use by then That is, the value of the previous THEN is used as an argument to the callback function of the next THEN (the previous promise THEN must return).

3. ResolvePromise (promise2, x, resolve, reject) is for incoming x parameter type judgment, The execution logic varies depending on the type, if x is promise2, reject(error), if JKQPromise, call recursively until resolve, if object or function Then. Call (x,(y)=>{// Continue type determination of y until resolve (promise2, y, resolve) reject); }, (r) => {reject(r); })

  1. The chained call to THEN returns a new promise object. If resolve is executed in the first promise, the value of the first resolve can be obtained by then. The new promise returned by then performs an internal type determination based on the return value of the then callback Then determine the state and value of the current promise

Then can also be executed if a catch is followed by a chained then because the catch is an exception and returns a promise object, and the value of the subsequent THEN uses the value before the catch. In the chain call, the state of the catch callback function is rejected if it throws an exception. If it is executed normally, the state is fulfilled fulfilled reason which will be continued by the subsequent catch