ES6——手把手实现一个简单的Promise

想要实现一个Promise,首先当然得先知道这个东西是什么,Promise对象是ES6给我们提供的一个解决异步回调的一个语法糖,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。把异步操作放入Promise对象中,等到Promise对象中的操作完成了,再继续执行then里面的操作。具体的使用就不说了,大概的使用方法如同下面。详情可以看ES6

    let p=new Promise(function (resolve,reject) {
        setTimeout(function () {
            resolve(2);
        },1000);
    });
    p.then(function (n) {
        console.log(n);
    },function (n) {
        console.log(n);
    });

那么接下来就来具体说说要怎么去实现一个Promise对象,这里我先用es5的语法实现一下,后面会附带用es6的语法,也就是用到了“类”这个概念

首先按照es5创建对象的套路,先来个初始化

 function Promise2(fn) {
    const _this = this;    //方便this改变时,能够继续调用
    this._queue = [];    //promise关键,一个函数队列,用于储存为能够开始执行的函数
    this._succ_res = null;     //用于存放成功时的参数
    this._err_res = null;    //用于存放失败时的参数
    this.status = '';    //Promise状态
    fn();     //传入Promise的回调函数
  }

我们知道Promise传进来的参数是一个函数,那么最主要的事情就是要在Promise里面去执行它。执行完之后呢,这个函数可能是执行成功的,也可能失败,所以如下图,我们可以看到有一个resolve和reject两个方法。因此我们需要在传进来的参数里面设置两个function。

function Promise2(fn) {
    ......
    fn(function (...arg) {
      //resolve
    }, function (...arg) {
      //reject
    })
  }

同时我们还有一个then的方法,这个时候就要搬出我们的原型了。那么then里面要做什么呢?在then里面,会被放入两个函数,一个表示成功后执行的,一个表示失败后执行的,所以then主要是要做下面的事

  1. 判断当前Promise的状态,Promise有3个状态,pending、fulfilled和rejected。简单讲就是,Promise的函数还没执行完、Promise的函数执行完了并且成功了、Promise执行完了但失败了,这三种状态。
  2. 如果未执行完:把then里面要执行的函数放在等待队列里面
  3. 如果执行完且成功:执行then中表示成功的函数
  4. 如果执行完但失败:执行then中表示失败的函数

所以Promise的then如下

Promise2.prototype={
    then:function (fn1, fn2) {
      let _this=this;
      if (_this.status == 'success') {
        fn1(..._this._succ_res);
      } else if (_this.status == 'error') {
        fn2(..._this._succ_res);
      } else {
        _this._queue.push({fn1, fn2});
      }
    }
  }

同样是我们在原来的函数里面,也要对状态的改变进行设置。而状态一旦确定下来也就不会再改变,那么,也就要先判断状态是否已经发生改变

fn(function (...arg) {
      //resolve
      if (_this.status != 'error') {    //判断状态是否已经变成失败
        _this.status = 'success';    //改变状态
        _this._succ_res = arg;    //传入resolve()中传给then的参数
        _this._queue.forEach(json => {    //执行结束后,看看队列里是否有函数,有的话执行第一个,并传入对应的参数
          json.fn1(...arg);
        });
      }
    }, function (...arg) {
      //reject
      if (_this.status != 'success') {    //判断状态是否已经变成成功
        _this.status = 'error';    //改变状态
        _this._err_res = arg;    //传入resolve()中传给then的参数
        _this._queue.forEach(json => {    //执行结束后,看看队列里是否有函数,有的话执行第二个函数,并传入对应的参数
          json.fn2(...arg);
        });
      }
    })

完整代码如下

  function Promise2(fn) {
    const _this = this;
    this._queue = [];
    this._succ_res = null;
    this._err_res = null;
    this.status = '';
    fn(function (...arg) {
      //resolve
      if (_this.status != 'error') {
        _this.status = 'success';
        _this._succ_res = arg;
        _this._queue.forEach(json => {
          json.fn1(...arg);
        });
      }
    }, function (...arg) {
      //reject
      if (_this.status != 'success') {
        _this.status = 'error';
        _this._err_res = arg;
        _this._queue.forEach(json => {
          json.fn2(...arg);
        });
      }
    })
  }
  Promise2.prototype={
    then:function (fn1, fn2) {
      let _this=this;
      if (_this.status == 'success') {
        fn1(..._this._succ_res);
      } else if (_this.status == 'error') {
        fn2(..._this._succ_res);
      } else {
        _this._queue.push({fn1, fn2});
      }
    }
  }


  let p2=new Promise2(function (resolve,reject) {
      setTimeout(function () {
          resolve(22);
      },1000);
      setTimeout(function () {
          reject(23);
      },500);
  });
  p2.then(function (n) {
    console.log(n);
  }, function (n) {
    console.log(n);
  })

点击:这个是用es6中的class实现的,其实差不多是一样的

最后来总结一下

Promise之所以能够把异步的东西按照同步的形式去执行,无非因为两点

  1. 当状态未发生改变时,能够将then中的函数暂时挂起
  2. 当状态改变时,能够调用其之前挂起的then队列

猜你喜欢

转载自blog.csdn.net/Yvan_Lin/article/details/81094968
今日推荐