实现一个简单的promise,更深刻的理解promise

在我刚刚接触Promise的时候,我一直想不通promise究竟是如何实现的,ta是怎么执行的?,Promise的链式和jq的链式一样吗?你是不是和我一样的困惑呢?那就和本文一起实现一个简单的promise吧,然后你就明白了!

在实现之前,先讲一下现实生活中的例子: 周六早上,小明的妈妈开始做饭,妈妈需要炒n个菜,可是没盐了,于是就让小明去买盐,小明的妈妈是一个很懂得利用时间的人,她是不会等着小明的,在小明买盐期间,妈妈还在炒菜,给菜都放进盘子里,一会小明回来了,妈妈直接将盐放进去了,你看中间是不是一点时间都没有浪费啊!Promise也是一样,从上到下一直走着,到resolve(小明回来了),存放回调函数的队列开始顺序执行(就好像妈妈拿着盐依次倒入每个菜盘)

先来一个基本的promise

看代码:

// executor是立即执行的 而then里面的onFullFilled, onRejected是先存起来形成一个队列,
// 等到resolve,或者reject之后执行

class Promise{
  constructor(executor){
    // 默认是等待状态
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    // 存放成功的回调
    this.onResolvedCallbacks = [];
    // 存放失败的回调
    this.onRejectedCallbacks = [];

    // resolve或者reject的时候 执行所有callback
    let resolve = (data) => {
      if (this.status === 'pending') {
        this.value = data;
        this.status = 'resolved';
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    let reject = (reason) => {
      this.reason = reason;
      this.status = 'rejected';
      this.onRejectedCallbacks.forEach(fn => fn())
    }

    try { // 执行时可能会发生异常
      executor(resolve, reject);
    } catch (e) {
      reject(e); // promise失败了
    }
  }

  // 此处的then方法主要是1,给所有的异步回调存起来
  then(onFulFilled, onRejected) {
    // 前两个判断是同步 用的
    if (this.status === 'resolved'){
      // 存放成功的回调
      this.onResolvedCallbacks.push(() => {
        onFulFilled(this.value);
      });
      this.onResolvedCallbacks.forEach(fn => fn())
    }else if (this.status === 'rejected') {
      // 存放失败的回调
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason);
      });
      this.onRejectedCallbacks.forEach(fn => fn())
    }else{
      // 存放成功的回调
      this.onResolvedCallbacks.push(() => {
        onFulFilled(this.value);
      });
      // 存放失败的回调
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason);
      });
    }

  }
}

module.exports = Promise;
复制代码

new Promise((resovle,reject) => {})这个时候是立即执行executor,理解的话你可以直接看作executor();有标志的状态status,有存放回调函数的数组,等等这些属性, 在promise的原型上有一个then方法, 同步的时候(假设都是成功的话): 在执行器里面直接resolve(data) 这时候then还没执行也就是说此时执行的循环回调函数数组是空的,所以在下面的then里面我们看到又去循环执行了一遍

if (this.status === 'resolved'){
      // 存放成功的回调
      this.onResolvedCallbacks.push(() => {
        onFulFilled(this.value);
      });
      this.onResolvedCallbacks.forEach(fn => fn())
    }
复制代码

在异步的时候: 这个then方法就做了一件事 就是将then里面的回调函数放到了一个数组队列里面, 当promise实例resolve的时候,依次执行该实例onResolvedCallbacks数组里面的回调,失败的时候也是如此。 这样就了解了promise实现的基本原理了。知道promise究竟是怎么执行的了。


再进一步来实现Promise的链式调用

我们知道jq的链式调用时返回了当前对象,所以可以链式调用,那Promise可以吗?显然不能,我们在上一篇文章就说过,一个promise的状态一旦转变就不可逆转,所以这个链式调用绝不是返回了当前对象,事实上是在内部重新new了一个promise,作为中转来处理各种情况,看代码实现:


function resolvePromise(x, resolve, reject){
  if(promise2 === x){   //x表示then成功的返回值,
      console.log('循环引用')
      return reject('不能自己引用自己')
  }
  // 判断x是不是promise
    
  if (x !==null && (typeof x === 'object' || typeof x === 'function')){
    let called;
    // try一下防止取then的时候出现异常
    try {
      let then = x.then;
      if(typeof then === 'function'){   //这里我们假设x有then方法,那么x就是promise
        then.call(x, y => {      //执行x身上的then方法 
          if(called) return;
          called = true;
          resolvePromise(y,resolve,reject);
        }, r => {
          if (called) return;
          called = true;
          reject(r);
        })
      }
    } catch (e) {
      
    }
  } else {
    resolve(x); // x就是一个普通值
  }
}

// exccutor是立即执行的 而then里面的onFullFilled, onRejected是先存起来形成一个队列,
// 等到resolve,或者reject之后执行(只考虑异步的情况)

class Promise{
  constructor(executor){
    // 默认是等待状态
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    // 存放成功的回调
    this.onResolvedCallbacks = [];
    // 存放失败的回调
    this.onRejectedCallbacks = [];

    // resolve或者reject的时候 执行所有callback
    let resolve = (data) => {
      if (this.status === 'pending') {
        this.value = data;
        this.status = 'resolved';
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    let reject = (reason) => {
      this.reason = reason;
      this.status = 'rejected';
      this.onRejectedCallbacks.forEach(fn => fn())
    }

    try { // 执行时可能会发生异常
      executor(resolve, reject);
    } catch (e) {
      reject(e); // promise失败了
    }
  }

  // 此处的then方法主要是1,给所有的异步回调存起来
  then(onFulFilled, onRejected) {
    let promise2;
    if (this.status === 'resolved'){
      // 存放成功的回调
      promise2 = new Promise((resolve, reject) => {
        this.onResolvedCallbacks.push(() => {
          let x = onFulFilled(this.value)
            resolvePromise(x, resolve, reject)
        });
      })
      
    }else if (this.status === 'rejected') {
      // 存放失败的回调
      promise2 = new Promise((resolve, reject) => {
        this.onRejectedCallbacks.push(() => {
          let x = onFulFilled(this.value)
          resolvePromise(x, resolve, reject)
        });
      })
      
    }else{
      // 存放成功的回调
      promise2 = new Promise((resolve, reject) => {
        this.onResolvedCallbacks.push(() => {      //resolve的时候触发执行这个 
          let x = onFulFilled(this.value)
          resolvePromise(x, resolve, reject)
        })
      })
      
      // 存放失败的回调
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason);
      });
    }
    return promise2

  }
}

module.exports = Promise;
复制代码

promise2就是在内部重新new的,如果上一个then的回调函数的返回值是普通值,那么就直接被promise2 resolve(普通值),如果上一个then返回的是一个promise,那么当前的这个then就会被绑定执行,这里的data当然就是返回的promise resolve的值

if(typeof then === 'function'){   //这里我们假设x有then方法,那么x就是promise
        then.call(x, y => {      //执行x身上的then方法 
          if(called) return;
          called = true;
          resolvePromise(promise2,y,resolve,reject);
        }, r => {
          if (called) return;
          called = true;
          reject(r);
        })
      }
复制代码

这就是上一篇文章所说的:

then的传递,如果then里面的回调返回的是一个Promise,那么就将这个Promise的resolve的值传递给下一个then的data值,如果返回的是一个普通值,那么就将这个普通值传递给下一个then的data值。

怎么样,对promise有更深刻的理解没?当然这篇promise的实现肯定会存在很多不足的地方,欢迎各位提出宝贵的意见或建议,也希望能帮助到你从中获得一些知识!下一篇我们来说说generator+co库和目前最流行的async await的使用以及注意事项!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值