PromiseA + specification

Common terminology

1) Promise: an object or function with a then method that behaves in accordance with the promiseA+ specification 4) Reason: a reject value. 5) exception: a throw exceptionCopy the code

Promise Status Indicates the status flow

Promise has three states: you can implement a flow between states. 1) Pending state The initial state can be changed into the fulfilled state through the pity state, which can be changed into the rejected state through the reject state 3) Reject When the execution fails, there must be a reason value when the reject state is changed to rejected stateCopy the code

Then Promises should provide a THEN method that accesses the final result

   promise.then(onFulfilled, onRejected)
Copy the code
1. OnFulfilled and onRejected must be a function. If it is not a function, OnFulfilled and onRejected must be a big pity. 3. Both onFulfilled and onRejected can only be called once, when the promise state becomes a big pity. OnFulfilled should be called. When the promise state becomes Rejected, onFulfilled should be called. 4. The THEN method can be called multiple times. After the promise state becomes "depressing", all ondepressing callbacks need to be executed in the order of "THEN", that is, in the order of registration. When the Promise state changes to Rejected, all onRejected callbacks need to be executed in the order of then, in the order of registration. 5. The then method returns a new promiseCopy the code
  resolvePromise(promise2, x, resolve, reject)
Copy the code
6.1 An exception is thrown if x and prommise2 are equal, If x is an object or function let then = x. teng if x. teng fails, then x is a promise. Call (x, resolvePromiseFn, rejectPromise) if then is not a function then resolveCopy the code

Implement a simple version of the promise based on the promiseA+ specification

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MPromise {
  FULFILLED_CALLBACK_LIST = []
  REJECTED_CALLBACK_LIST =[]
  _status = PENDING

  constructor (fn) {
    this.status = PENDING;
    this.value = null;
    this.reason = null;
    try {
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (err) {
      this.reject(err);
    }
  }

  get status () {
    return this._status;
  }

  set status (newStatus) {
    this._status = newStatus;
    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;
    }
  }

  resolve (value) {
    if (this.status ! == PENDING) {return;
    }
    this.value = value;
    this.status = FULFILLED;
  }

  reject (reason) {
    if (this.status ! == PENDING) {return;
    }
    this.reason = reason;
    this.status = REJECTED;
  }

  then (onFulfilled, onRejected) {
    const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value= > value;
    const realOnRejected = this.isFunction(onRejected) ? onRejected : reason= > { throw reason; };

    const promise2 = new MPromise((resolve, reject) = > {
      const fulfilledMicroTask = () = > {
        queueMicrotask(() = > {
          try {
            const x = realOnFulfilled(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch(err) { reject(err); }}); };const rejectedMicroTask = () = > {
        queueMicrotask(() = > {
          try {
            const x = realOnRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch(err) { reject(err); }}); };switch (this.status) {
        case FULFILLED:
          fulfilledMicroTask();
          break;
        case REJECTED:
          rejectedMicroTask();
          break;
        case PENDING:
          this.FULFILLED_CALLBACK_LIST.push(fulfilledMicroTask);
          this.REJECTED_CALLBACK_LIST.push(rejectedMicroTask);
          break; }});return promise2;
  }

  // core resolves a promise
  resolvePromise (promise2, x, resolve, reject) {
    // if x is equal to promise2, throw an error to avoid an infinite loop
    if (x === promise2) {
      return reject(TypeError('the x and promise are the same'));
    }
    // x is an MPromise instance
    if (x instanceof MPromise) {
      x.then(y= > {
        this.resolvePromise(promise2, y, resolve, reject);
      }, reject);
    }
    // is a function or an object
    if (this.isFunction(x) || typeof x === 'object') {
      if (x === null) {
        return resolve(x);
      }
      let then = null;
      try {
        then = x.then;
      } catch (err) {
        return reject(err);
      }
      if (this.isFunction(then)) {
        let called = false;
        then.call(x,
          y= > {
            if (called) {
              return;
            }
            called = true;
            this.resolvePromise(promise2, y, resolve, reject);
          },
          r= > {
            if (called) {
              return;
            }
            called = true; reject(r); }); }else{ resolve(x); }}else{ resolve(x); }}// catch
  catch (onRejected) {
    return this.then(null, onRejected)
  }


  Static methods can be called directly

  static resolve (value) {
    if (value instanceof MPromise) {
      return value;
    }
    return new MPromise((resolve, reject) = > {
      resolve(value);
    });
  }

  // reject
  static reject (reason) {
    return new MPromise((resolve, reject) = > {
      reject(reason);
    });
  }

  // race: The race method has a Promise that subsequent code will not execute after successful execution
  static race (promiseList = []) {
    return new MPromise((resolve, reject) = > {
      const len = promiseList.length;
      if(! len) {return resolve();
      }
      for (let i = 0; i < len; i++) {
        MPromise.resolve(promiseList[i]).then(
          value= > resolve(value),
          reason= >reject(reason) ); }}); }// all: Promise. All can wrap multiple Promise instances into a new Promise instance. Promise.all array of success resultsSame order as the array passed instatic all (promiseList = []) {
    return new MPromise((resolve, reject) = > {
      const len = promiseList.length;
      let resolvedNum = 0;
      const resolvedValueList = new Array(len);
      for (let i = 0; i < len; i++) {
        MPromise.resolve(promiseList[i]).then(value= > {
          resolvedNum++;
          resolvedValueList[i] = value;
          if(resolvedNum === len) { resolve(resolvedValueList); }},reason= >reject(reason)); }}); }// the utility function checks if it is function
  isFunction (value) {
    return typeof value === 'function'; }}Copy the code