usage

new Promise((resolve, reject) = > {
	// Asynchrony succeeds in executing resolve, otherwise executing reject
}).then((res) = > {
	// Resolve triggers the first callback to execute
}, (err) => {
	// Reject triggers the second callback to be executed
}).then(res= > {
// Ensure that the then method still returns a promise
// This is the way to make chained calls
}).catch(reason= >{});// Wait for all promises to execute successfully
// If there is a failure, catch will be executed
Promise.all([promise1, ...] ).then();Copy the code

First, try the knife

Initial realization Promise:

1. Achieve three states: ‘pending ‘, ‘fulfilled’, ‘rejected’

2. Can realize the then method of two callback function processing

//promise.js
class Promise{
  // Pass an asynchronous function in
  constructor(excutorCallBack){
    this.status = 'pending';
    this.value = undefined;
    this.fulfillAry = [];
    this.rejectedAry = [];
    / / = > Excutor execution
    let resolveFn = result= > {
      if(this.status ! = ='pending') return;
      let timer = setTimeout((a)= > {
        this.status = 'fulfilled';
        this.value = result;
        this.fulfillAry.forEach(item= > item(this.value));
      }, 0);
    };
    let rejectFn = reason= > {
      if(this.status ! = ='pending')return;
      let timer = setTimeout((a)= > {
        this.status = 'rejected';
        this.value = reason;
        this.rejectedAry.forEach(item= > item(this.value))
      })
    };
    try{
      // Execute this asynchronous function
      excutorCallBack(resolveFn, rejectFn);
    } catch(err) {
      //=> Exception information is processed according to the rejected state
      rejectFn(err);
    }
  }
  then(fulfilledCallBack, rejectedCallBack) {
    // The resolve and reject functions are actually microtasks
    // So they are not executed immediately, but after the then call completes
    this.fulfillAry.push(fulfilledCallBack);
    this.rejectedAry.push(rejectedCallBack);
    // After a push, they are executed}}module.exports = Promise;

Copy the code

The test is as follows:

let Promise = require('./promise');

let p1 = new Promise((resolve, reject) = > {
  setTimeout((a)= > {
    Math.random()<0.5? resolve(100):reject(- 100.);
  }, 1000)
}).then(res= > {
  console.log(res);
}, err => {
  console.log(err);
})

Copy the code

Two, complete the chain effect

The biggest hurdle is the implementation of chained calls, specifically the then method.

  //then pass in two functions
  then(fulfilledCallBack, rejectedCallBack) {
    // Make sure both are functions
    typeoffulfilledCallBack ! = ='function' ? fulfilledCallBack = result= > result:null;
    typeofrejectedCallBack ! = ='function' ? rejectedCallBack = reason= > {
      throw new Error(reason instanceof Error? reason.message:reason);
    } : null
    // Return a new Promise object called "New Promise"
    return new Promise((resolve, reject) = > {
      // Note that this refers to the current Promise object, not the new Promise
      // It is important to repeat:
      // The resolve and reject functions of the current Promise(not the new Promise return here) are actually a microtask
      // So they are not executed immediately, but after the then call completes
      this.fulfillAry.push((a)= > {
        try {
          // Execute the methods in the then
          // The purpose of execution has been achieved
          let x = fulfilledCallBack(this.value);
          // The next step after execution is to record the execution status and determine how the new Promise will behave
          // If the return value x is a Promise object, then the operation is performed
          // If it is not a Promise, call the new Promise's resolve function directly,
          // The new promises are now empty after the new promises' THEN operations. The resolve implementation of the new Promise
          x instanceof Promise ? x.then(resolve, reject):resolve(x);
        }catch(err){
          reject(err)
        }
      });
      // The same is true
      this.rejectedAry.push((a)= > {
        try {
          let x = this.rejectedCallBack(this.value);
          x instanceof Promise ? x.then(resolve, reject):resolve(x);
        }catch(err){
          reject(err)
        }
      })
    }) ;
  }
Copy the code

Test cases:

let p1 = new Promise((resolve, reject) = > {
  setTimeout((a)= > {
    Math.random()<0.5? resolve(100):reject(- 100.);
  }, 1000)})let p2 = p1.then(result= > {
  // Then returns a new Promise
  return result + 100;
})
let p3 = p2.then(result= > {
  console.log(result);
}, reason => {
  console.log(reason)
})
Copy the code

A simple diagram to simulate the internal flow of chained calls:

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

Third, the Promise. All ()

Next, implement promise.all ()

// For static methods of the class, not on the prototype
static all(promiseAry = []) {
    let index = 0, 
        result = [];
    return new Promise((resolve, reject) = > {
      for(let i = 0; i < promiseAry.length; i++){
        promiseAry[i].then(val= > {
          index++;
          result[i] = val;
          if( index === promiseAry.length){ resolve(result) } }, reject); }})}Copy the code

Four, Promise. Race ()

Next comes the RACE method

static race(promises) {
  return new Promise((resolve, reject) = > {
    if (promises.length === 0) {
      return;
    } else {
      for(let i = 0; i < promises.length; i++){
        promises[i].then(val= > {
            resolve(result);
            return; } }, reject); }}}); }Copy the code

Five, the Promise. The resolve ()

static resolve (value) {
    if (value instanceof Promise) return value
    return new Promise(resolve= > resolve(value))
}
Copy the code

Six, Promise. Reject ()

static reject (value) {
    return new Promise((resolve, reject) = > reject(value))
}
Copy the code

The complete code

Now write a simple but fully functional Promise and you’re done.

class Promise{
  constructor(excutorCallBack){
    this.status = 'pending';
    this.value = undefined;
    this.fulfillAry = [];
    this.rejectedAry = [];
    / / = > Excutor execution
    let resolveFn = result= > {
      if(this.status ! = ='pending') return;
      let timer = setTimeout((a)= > {
        this.status = 'fulfilled';
        this.value = result;
        this.fulfillAry.forEach(item= > item(this.value));
      }, 0);
    };
    let rejectFn = reason= > {
      if(this.status ! = ='pending')return;
      let timer = setTimeout((a)= > {
        this.status = 'rejected';
        this.value = reason;
        this.rejectedAry.forEach(item= > item(this.value))
      })
    };
    try{
      excutorCallBack(resolveFn, rejectFn);
    } catch(err) {
      //=> Exception information is processed according to the rejected state
      rejectFn(err);
    }
  }
  then(fulfilledCallBack, rejectedCallBack) {
    typeoffulfilledCallBack ! = ='function' ? fulfilledCallBack = result= > result:null;
    typeofrejectedCallBack ! = ='function' ? rejectedCallBack = reason= > {
      throw new Error(reason instanceof Error? reason.message:reason);
    } : null

    return new Promise((resolve, reject) = > {
      this.fulfillAry.push((a)= > {
        try {
          let x = fulfilledCallBack(this.value);
          x instanceof Promise ? x.then(resolve, reject ):resolve(x);
        }catch(err){
          reject(err)
        }
      });
      this.rejectedAry.push((a)= > {
        try {
          let x = this.rejectedCallBack(this.value);
          x instanceof Promise ? x.then(resolve, reject):resolve(x);
        }catch(err){
          reject(err)
        }
      })
    }) ;
  }
  catch(rejectedCallBack) {
    return this.then(null, rejectedCallBack);
  }
  static all(promiseAry = []) {
    let index = 0, 
        result = [];
    return new Promise((resolve, reject) = > {
      for(let i = 0; i < promiseAry.length; i++){
        promiseAry[i].then(val= > {
          index++;
          result[i] = val;
          if( index === promiseAry.length){ resolve(result) } }, reject); }})}static race(promiseAry) {
  return new Promise((resolve, reject) = > {
    if (promiseAry.length === 0) {
      return;
    }
    for (let i = 0; i < promiseAry.length; i++) {
      promiseAry[i].then(val= > {
        resolve(val);
        return; }, reject); }})}static resolve (value) {
    if (value instanceof Promise) return value
    return new Promise(resolve= > resolve(value))
}
static reject (value) {
    return new Promise((resolve, reject) = > reject(value))
}
}

module.exports = Promise;

Copy the code