实现es6的promise

今天学习一下别人实现的 promise 的代码。

这是源码

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
let id = 0;

/*
 *value状态为执行成功事件的入参,deferreds保存着状态改变之后的需要处理的函数以及promise子节点,构造函
 *数里面应该包含这三个属性的初始化
 */

class Promise {
  constructor(callback) {
    this.id = id;
    this.status = PENDING;
    this.value = null;
    this.defferd = [];
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
    callback(this.resolve, this.reject);
    id++;
  }

  //触发改变promise状态到FULFILLED
  resolve(result) {
    console.log(`id: ${this.id} resolve`);
    this.status = FULFILLED;
    this.value = result;
    this.done();
  }

  //触发改变promise状态到REJECTED
  reject(error) {
    this.status = REJECTED;
    this.value = error;
    this.done();
  }

  // 触发promise defferd里面需要执行的函数
  // 只有在resolve和reject的时候才会执行
  done() {
    if (this.status === PENDING) return;
    var defferd = this.defferd;

    // if (this.isAsync && this.prevPromise) {
    //   this.prevPromise.defferd = [];
    //   this.prevPromise.resolve();
    // }

    // 如果有defferd,就说明当前是异步操作,异步操作执行resolve的时候,此时defferd中已经包括了下一个then函数
    // 如果没有,就说明当前是同步操作,不需要再次执行then函数了。
    for (var i = 0; i < defferd.length; i++) {
      this.handle(defferd[i]);
    }
  }

  /* 处理defferd
   * 如果是同步操作的时候,则直接执行then函数中传递的success或者fail
   * 如果是异步操作,那么会等异步操作执行完,再去执行then函数中传递的success或者fail
   * 同时这里也会判断success和fail是否还是异步操作
   * --------------
   * 这里的thenObj指的是
   * {
   *    onfulfiled:  传递给当前promise.then的success函数,
   *    onrejected: 传递给当前promise.then的fail函数,
   *    promise: 当前promise重新生成的promise
   *    defferd: 当前promise需要执行的defferd
   * }
   */
  handle(thenObj) {
    if (!thenObj) {
      return;
    }
    var value = this.value;
    var status = this.status;
    var p;
    if (status === FULFILLED && typeof thenObj.onfulfiled == 'function') {
      p = thenObj.onfulfiled(value);
    }
    if (status === REJECTED && typeof thenObj.onrejected == 'function') {
      p = thenObj.onrejected(value);
    }
    /* new
     *如果then中是一个新的Promise对象,则将then函数的defferd函数传给新的promise对象
     *这里一定要搞清楚this,thenObj等对象的关系
     *这里的this指向的是实例,如果then中是新的Promise对象,则指向改对象
     *如果then中不是新的Promise对象,则this指向上个then的作用域,并立即执行resolve()函数
     */

    /** new
     * 执行defferd函数
     * 如果执行的success或fail函数还是返回了promise,就说明这个执行的函数是异步的,需要等待其完成后再执行defferd
     * 所以这个时候需要将下个then函数的defferd传递给当前返回的promise,好让他在异步操作完成后继续执行下一个then函数
     *
     * 如果不是promise,那么直接resolve(),修改status,并执行后面的then
     */
    if (p && p.constructor === Promise) {
      console.log(`handle promise id:${p.id}`);
      p.defferd = thenObj.promise.defferd;
      p.isAsync = true;
      p.prevPromise = thenObj.promise;
    } else {
      thenObj.promise.resolve();
    }
  }

  /* 执行then函数
   * 储存then函数里面的事件success和fail
   * 根据status判断上一个函数是否异步
   * 如果是同步,则直接执行handle(等于直接直接执行success和fail函数)
   * 如果是异步,则将当前的thenObj存入到上一个函数的defferd中
   * ----
   * 最后返回一个新的promise对象,可以继续执行下一个then函数
   * 并且可以将下一个then函数中的defferd添加到thenObj.promise.defferd中
   *
   */
  then(success, fail) {
    var thenObj = {
      onfulfiled: success,
      onrejected: fail,
    };
    var status = this.status;
    // key!!!
    // 这里是关键,默认生成一个不会resolve的promise
    thenObj.promise = new Promise(function () {});
    console.log('promise id: ' + thenObj.promise.id);
    // 如果还在PENDING,就说明这个时候是异步,需要讲thenObj添加进当前promise的defferd,等异步操作完成再执行defferd
    if (status === PENDING) {
      this.defferd.push(thenObj);
    } else if (status === FULFILLED || status === REJECTED) {
      // 如果直接FULFILLED或者REJECTED,就说明在执行then函数的时候已经完成函数执行, 那么直接处理thenObj即可。
      this.handle(thenObj);
    }
    /*
     * 这里返回thenObj.promise对象,所以下一个then中的this就指向thenObj.promise
     */
    return thenObj.promise;
  }
}

let promise1 = new Promise((resolve, reject) => {
  resolve(99);
})
  .then((res) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(res + 1), 1000);
    });
  })
  .then((res) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(res + 1), 1000);
    });
  })
  .then((res) => {
    return res + 1;
  })
  .then((res) => {});

/**
 *  id: 0 resolve
 *  promise id: 1                       第一个then函数生成的promise
 *  handle promise id:2    因为同步,需要执行then的success来判断函数类型,所以生成success的promise
 *  promise id: 3                       第二个then函数生成的promise
 *  promise id: 4                       第三个then函数生成的promise
 *  promise id: 5                       第死个then函数生成的promise
 *  id: 2 resolve           第一个异步的then函数执行完成
 *  handle promise id:6    开始执行第二个异步的then函数,执行函数体,生成success的promise
 *  id: 6 resolve           第二个异步的then函数执行完成
 *  id: 4 resolve           第三个then函数生成的promise
 *  id: 5 resolve           第四个then函数生成的promise
 *
 *
 *  可能会疑问为什么promise id为1和3的为什么没有执行resolve,这是因为1和3的promise的success返回的还是promise
 *  那么就永远都不会自己执行resolve函数了
 *  如果想让1和3在2和6在执行完异步操作并resolve后,也一并resolve,可以将上面注释的代码放开,就能实现。
 *  主要就是在异步操作执行完,在执行defferd之前,获取父promise,清除掉他的defferd,然后执行resolve.
 */

花了差不多快一天的时间,彻底理解了该 promise 的实现原理,并做了部分修改,虽然可能花了比较多的时间,但是我觉得这还是非常值得的。

通过这次理解,我学到了如何巧妙的保存并传递 then 中回调函数,还有设计的一些思想,这里搞懂 this 的指向我觉得异常重要!

blog comments powered by Disqus
目 录