Promise练习三(手写简版promise + 符合promise/A+规范的promise)

JavaScript实现一个简易的Promise对象

class MyPromise {
  constructor(handleFn) {
    // Promise的状态
    this.PromiseState = "pending";
    // Promise的结果
    this.PromiseValue = null;

    // 画重点!!!这两个list是为了将下一个Promise与当前Promise相关联
    this._toNextResolve = [];
    this._toNextReject = [];
    // Promise接收的函数参数
    handleFn(this.triggerResolve.bind(this), this.triggerReject.bind(this));
  }

  // resolve处理
  triggerResolve(data) {
    // 这里使用setTimeout的原因是:确保resolve处理函数在handleFn所处的事件循环后以新的堆栈异步执行。(参见:2.4)
    setTimeout(() => {
      // Promise的状态不是pending时,不能被修改状态。(参见:1)
      if (this.PromiseState !== "pending") return;
      // 修改Promise的状态和值
      this.PromiseState = "fullfilled";
      this.PromiseValue = data;
      this._toNextResolve.forEach(item => item(data));
      this._toNextResolve = [];
    }, 0);
  }

  // reject处理,同上
  triggerReject(data) {
    setTimeout(() => {
      if (this.PromiseState !== "pending") return;
      this.PromiseState = "rejected";
      this.PromiseValue = data;
      this._toNextReject.forEach(item => item(data));
      this._toNextReject = [];
    }, 0);
  }

  // 将多个Promise包装成一个新的Promise实例,并在所有异步操作执行完后执行回调
  static all(list) {
    const result = [];
    let count = 0;
    return new MyPromise(function(resolve, reject) {
      for (let [i, MyPromiseInstance] of list.entries()) {
        MyPromiseInstance.then(
          res => {
            result[i] = res;
            count++;
            if (count === list.length) resolve(result);
          },
          err => {
            reject(err);
          }
        );
      }
    });
  }

  static race(list) {
    return new MyPromise(function(resolve, reject) {
      for (let [i, MyPromiseInstance] of list.entries()) {
        MyPromiseInstance.then(
          res => {
            resolve(res);
          },
          err => {
            reject(err);
          }
        );
      }
    });
  }

  // static resolve(val) {
  //   return new MyPromise(resolve=>resolve(val));
  // }

  // static reject(val) {
  //   return new MyPromise(resolve=>{}, reject=>reject(val));
  // }
}

MyPromise.prototype.then = function(onResolved, onRejected) {
  const { PromiseState, PromiseValue } = this;

  // then方法必须返回一个Promise对象。(参见:2.7)
  return new MyPromise((onNextResolved, onNextRejected) => {
    function onLastFullFilled(val) {
      if (typeof onResolved !== "function") {
        // 如果onResolved不是函数,则需要忽略他。(参见:2.1)
        onNextResolved(val);
      } else {
        const res = onResolved(val);
        if (res && typeof res.then === "function") {
          // 若res 是一个 promise
          res.then(onNextResolved);
        } else {
          // 若res 非 promise,则直接执行下一个 onNextResolved
          onNextResolved(res);
        }
      }
    }
    function onLastRejected(val) {
      if (typeof onRejected !== "function") {
        // 如果onRejected不是函数,则需要忽略他。(参见:2.1)
        onNextRejected(val);
      } else {
        const res = onRejected(val);
        if (res && typeof res.then === "function") {
          // 若res 是一个 promise
          res.then(onNextRejected);
        } else {
          // 若res 非 promise,则直接执行下一个 onNextRejected
          onNextRejected(res);
        }
      }
    }
    switch (PromiseState) {
      case "pending": {
        this._toNextResolve.push(onLastFullFilled);
        this._toNextReject.push(onLastRejected);
        break;
      }
    }
  });
};

const p1 = function() {
  return new MyPromise(function(resolve, reject) {
    setTimeout(function() {
      const random = Math.random() * 10;
      if (random > 5) {
        resolve("已完成1:" + random);
      } else {
        reject("已拒绝1:" + random);
      }
    }, 1000);
  });
};

const p2 = function() {
  return new MyPromise(function(resolve, reject) {
    const random = Math.random() * 10;
    resolve("已完成2:" + random);
  });
};

const p3 = function() {
  return new MyPromise(function(resolve, reject) {
    const random = Math.random() * 10;
    resolve("已完成3:" + random);
  });
};

p1().then(
  res => {
    console.log('then方法:');
    console.log(res);
  },
  err => {
    console.log('then方法:');
    console.log(err);
  }
);

MyPromise.all([p1(), p2(), p3()]).then(
  res => {
    console.log('all方法:');
    console.log(res);
  },
  err => {
    console.log('all方法:');
    console.log(err);
  }
);

MyPromise.race([p1(), p2(), p3()]).then(
  res => {
    console.log('race方法:');
    console.log(res);
  },
  err => {
    console.log('race方法:');
    console.log(err);
  }
);

按照Promise/A+规范,使用typescript实现Promise

  // Promise/A+ 1.3: "value" is any legal JavaScript Value.
  type PromiseValue = any;
  // Promise/A+ 1.5: "reason" is a  value that indicates why a promise was rejected.
  type PromiseReason = any;
  // Promise/A+ 2.2.1: Both onFulfilled and onRejected are optional arguments.
  type onFulfilled = any;
  type onRejected = any;
  // Promise/A+ 2.1: A Promise must be in one of three states:  pending, fulfilled, or rejected.
  enum PromiseState {
    Pending = "pending",
    Fulfilled = "fulfilled",
    Rejected = "rejected"
  }
  type resolve = (value: PromiseValue) => void;
  type reject = (reason: any) => void;
  type executor = (resolve: resolve, reject: reject) => void;

  // 类型判断
  const ToString = Object.prototype.toString;
  const IsFunctionType = (val: any): boolean => ToString.call(val) === "[object Function]";
  const IsObjectType = (val: any): boolean => ToString.call(val) === "[object Object]";
  const IsNullType = (val: any): boolean => ToString.call(val) === "[object Null]";
  const IsPromiseType = (val: any): boolean => val instanceof PromiseImplement;
  const hasAttribute = (target: any, name: string): boolean => name in target;

  const promiseProcedure = function(promise: PromiseImplement, x: any, resolve: resolve, reject: reject){
    // Promise/A+ 2.3.1: If promise and x refer to the same object, reject promise with a TypeError as the reason.
    if(promise == x){
      const err = new TypeError('Endless loop detected for Promise');
      return reject(err);
    }
    // Promise/A+ 2.3.2: If x is a promise, adopt its state
    if(IsPromiseType(x)){
      if(x.state == PromiseState.Pending){
        // Promise/A+ 2.3.2.1: If x is pending, promise must remain pending until x is fullfilled or rejected.
        x.then((val: PromiseValue) => promiseProcedure(promise, val, resolve, reject), reject);
      }else{
        // Promise/A+ 2.3.2.2: If/when x is fulfilled, fulfill promise with the same value.
        // Promise/A+ 2.3.2.3 If/when x is rejected, reject promise with the same reason.
        x.then(resolve, reject);
      }
    }else if(IsObjectType(x) || IsFunctionType(x)){
      let ignored: boolean = false;
      // Promise/A+ 2.3.3: If x is an Object or funciton
      try{
        // Promise/A+ 2.3.3.1: let then be x.then.
        let then = x.then;      
        if(IsFunctionType(then)){
          const resolvePromise = (y: any) => {
            // Promise/A+ 2.3.3.3.1: If/when resolvePromise is called with a value y, run[[Resolve]](promise, y)
            if(ignored) return;
            ignored = true;
            promiseProcedure(x, y, resolve, reject);
          }
          const rejectPromise = (r: any) => {
            // Promise/A+ 2.3.3.3.2: If/when rejectPromise is called with a reason r, reject promise with r.
            if(ignored) return;
            ignored = true;
            return reject(r);
          }
          // Promise/A+ 2.3.3.3: If then is a function,call it with x as this, first argument resolvePromise, and second argument rejectPromsie
          then(resolvePromise, rejectPromise).bind(x);
        }else {
          // Promise/A+ 2.3.3.4: If then is not a function, fulfill promise with x.
          resolve(x);
        }
      }catch(e){
        if(ignored) return;
        // Promise/A+ 2.3.3.2: if retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
        reject(e);
      }
    }else {
      // Promise/A+ 2.3.4: If x is not an object or function, fulfill promise with x
      resolve(x);
    }
  }

  class PromiseImplement {
    state: PromiseState;
    value: PromiseValue;
    reason: PromiseReason;
    onFulfilledCallbacks: onFulfilled[] = [];
    onRejectedCallbacks: onRejected[] = [];

    constructor(executor: executor) {
      this.state = PromiseState.Pending;

      if (!IsFunctionType(executor)) {
        throw new TypeError(`Promise resolver ${executor} is not a function`);
      }
      if (!(this instanceof PromiseImplement)) {
        throw new TypeError("undefined is not a promise");
      }
      executor(this.triggerResolve.bind(this), this.triggerReject.bind(this));
    }
    triggerResolve(val) {
      setTimeout(()=>{
        if(this.state !== PromiseState.Pending) return;
        this.state = PromiseState.Fulfilled;
        this.value = val;
        this.onFulfilledCallbacks.forEach((onFulfilled: onFulfilled)=>onFulfilled());
        this.onFulfilledCallbacks = [];
      }, 0);
    }
    triggerReject(reason) {
      setTimeout(()=>{
        if(this.state !== PromiseState.Pending) return;
        this.state = PromiseState.Rejected;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((onRejected: onRejected)=>onRejected());
        this.onRejectedCallbacks = [];
      },0)
    }

    // Promise/A+ 2.2: A promise must provide a then method to access its current or eventual valur or reason.
    // Promise/A+ 2.2: A promise's then method accepts two arguments: onFulfilled, onRejected
    then(onFulfilled?: onFulfilled, onRejected?: onRejected) {
      // Promise/A+ 2.2.1.1: If onFulfilled is not a function, it must be ignored.
      // Promise/A+ 2.2.5: onFulfilled must be called as function
      !IsFunctionType(onFulfilled) &&
        (onFulfilled = (PromiseValue: PromiseValue) => PromiseValue);
      // Promise/A+ 2.2.1.2: If onRejected is not a function,it must be ignored.
      // Promise/A+ 2.2.5: onRejected must be called as function
      !IsFunctionType(onRejected) &&
        (onRejected = (PromiseReason: PromiseReason) => PromiseReason);

      // Promise/A+ 2.2.7: then must return a promise.
      const promise2 = new PromiseImplement((resolve, reject)=>{
        if(this.state == PromiseState.Pending){
          // Promise/A+ 2.2.2: If onFulfilled is a function, it must be called after promise is fulfilled,with promise's value as its first argument.
          this.onFulfilledCallbacks.push(()=>{
            const x = onFulfilled(this.value);
            promiseProcedure(this, x, resolve, reject);
          });
          // Promise/A+ 2.2.3: If onRejected is a function, it must be called after promise is rejected,with promise's reason as its first argument.
          this.onRejectedCallbacks.push(()=>{
            const x = onRejected(this.reason);
            promiseProcedure(this, x, resolve, reject);
          });
        }
      });
      return promise2;
    }
  }

  const p1 = function() {
    return new PromiseImplement(function(resolve, reject) {
      setTimeout(function() {
        const random = Math.random() * 10;
        if (random > 5) {
          resolve("已完成1:" + random);
        } else {
          reject("已拒绝1:" + random);
        }
      }, 1000);
    });
  };
  p1().then((res)=>{
    console.log(res)
  }, (err)=>{
    console.log(err);
  }).then((res)=>{
    console.log('完成2:' + res);
  },(err)=>{
    console.log('拒绝3:' + err);
  });

你可能感兴趣的:(javascript)