手写Promise核心代码

初始结构

  • 原生的promise使用new创建一个实例,传入的参数是一个函数,会自动执行。原生的Promise可以传入resolve和reject两个参数。调用resolve是以函数形式调用的:resolve(),可以传入参数resolve('okok')

  • promise有三种状态:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。一个 Promise 对象只能从 Pending 状态转换到 Fulfilled 或 Rejected 状态,并且状态转换是不可逆的。

let promise = new Promise((resolve,reject) =>{
    resolve('okok');
});
class MyPromise{
  static PENDING = '待定'; static FULFILLED='成功'; static REJECTED = '失败';
  constructor(func){
    this.status = MyPromise.PENDING;
    this.result = null;//每个实例都有result属性
    func(this.resolve, this.reject);
  }
  resolve(result){
      if(this.status === MyPromise.PENDING){
      this.status = this.FULFILLED
      this.result = result;//把参数赋值给实例的result属性
    }
  }
  reject(result){
      if(this.status === MyPromise.PENDING){
      this.status = this.REJECTED;
      this.result = result
    }
  }
}

坑点:this指向问题

  • 上面代码执行结果:
    image

  • 分析原因:new一个新实例的时候执行的是constructor里的内容,在新实例被创建后再在外部环境下执行resolve,相当于不在class内部使用这个this,外部没有所以会报undefined。

  • 解决办法:使用bind绑定:固定 this指向,确保 resolve和 reject的 this始终是 MyPromise实例

class MyPromise{
  static PENDING = '待定'; static FULFILLED='成功'; static REJECTED = '失败';
  constructor(func){
    this.status = MyPromise.PENDING;
    this.result = null;
    func(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(result){
      if(this.status === MyPromise.PENDING){
      this.status = this.FULFILLED
      this.result = result
    }
  }
  reject(result){
      if(this.status === MyPromise.PENDING){
      this.status = this.REJECTED;
      this.result = result
    }
  }
}

then

  • then方法可以传入两个参数。两个参数都是函数。一个是当状态为成功时执行的代码,一个是当状态为失败时执行的代码
let promise = new Promise((resolve,reject) =>{
    resolve('okok');
    reject('nono');
});
promise.then(
  result => {console.log(result)},
  (error) => {console.log(error.message);}
);

image

  • 执行结果只有一个,所以手写时进行判断。如果当前实例的状态为成功的话,执行传进来的onFULFILLED函数,并传入前面保留的result属性值;错误类似
class MyPromise {
  static PENDING = "待定";
  static FULFILLED = "成功";
  static REJECTED = "失败";
  constructor(func) {
    this.status = MyPromise.PENDING;
    this.result = null;
    func(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(result) {
    if (this.status === MyPromise.PENDING) {
      this.status = this.FULFILLED;
      this.result = result;
    }
  }
  reject(result) {
    if (this.status === MyPromise.PENDING) {
      this.status = this.REJECTED;
      this.result = result;
    }
  }
  then(onFULFILLED, onREJECTED) {
    if (this.status === MyPromise.FULFILLED) {
        onFULFILLED(this.result);
    }
    if (this.status === MyPromise.REJECTED) {
        onREJECTED(this.result);
    }
  }
}

执行异常

  • 执行函数里面抛出错误是会触发拒绝方法的。调用then可以把错误信息作为内容输出出来

image

  • 手写实现同样功能。在执行resolve和reject前进行判断,如果有报错就把错误信息传给reject方法,并直接执行reject方法。这里不用this绑定:这里是直接执行,不是创建实例后再执行。
constructor(func) {
    this.status = MyPromise.PENDING;
    this.result = null;
    try{
      func(this.resolve.bind(this), this.reject.bind(this))
    }catch(error){
      this.reject(error)
    }
  }

then的参数

  • 原生promise里规定then的两个参数如果不是函数的话就要忽略

image

  • then函数中使用条件运算符:把不是函数的参数改为函数
then(onFULFILLED, onREJECTED) {
    onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : ()=>{}
    onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : ()=>{}
    if (this.status === MyPromise.FULFILLED) {
        onFULFILLED(this.result);
    }
    if (this.status === MyPromise.REJECTED) {
        onREJECTED(this.result);
    }
  }

异步

  • 原生的异步执行顺序:
    image

  • 给手写的代码在then方法里面添加setTimeout就可以了,需要在if判断状态符合再添加异步

then(onFULFILLED, onREJECTED) {
    onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : () => {};
    onREJECTED = typeof onREJECTED === "function" ? onREJECTED : () => {};
    if (this.status === MyPromise.FULFILLED) {
      setTimeout(() => {
        onFULFILLED(this.result);
      });
    }
    if (this.status === MyPromise.REJECTED) {
      setTimeout(() => {
        onREJECTED(this.result);
      });
    }
  }

回调保存

  • 原生
    image

  • 手写
    image

  • 手写的结果对比原生差了resolve的执行的okok。原因:then方法里面是根据条件判断来执行的代码,没有符合的状态就不会执行。then里面没有定义待定状态应该做什么。

  • 解决:then方法中添加待定的情况。这个时候resolve和reject还没获取到任何值。必须让then稍后执行,等resolve执行了再执行。1、为了保留then里的函数,创建数组来保存函数,在实例化的时候就让每个实例都有这两个数组。一个保存resolve函数,一个保存reject函数。2、当状态是待定时,把then里的两个参数放在两个数组里。3、执行resolve/reject时遍历自身的callbacks数组,有then保存过来的待执行的函数逐个执行。

class MyPromise{
  static PENDING = '待定'; static FULFILLED='成功'; static REJECTED = '失败';
  constructor(func){
    this.status = MyPromise.PENDING;
    this.result = null;
    this.resolveCallbacks = [];//第一步
    this.rejectCallbacks = [];//第一步
    try{
      func(this.resolve.bind(this), this.reject.bind(this))
    }catch(error){
      this.reject(error)
    }
  }
  resolve(result){
      if(this.status === MyPromise.PENDING){
      this.status = this.FULFILLED
      this.result = result
      this.resolveCallbacks.forEach(callback => {callback(result)})//第三步
    }
  }
  reject(result){
      if(this.status === MyPromise.PENDING){
      this.status = this.REJECTED;
      this.result = result
      this.rejectCallbacks.forEach(callback => {callback(result)})//第三步
    }
  }
  then(onFULFILLED, onREJECTED){
      onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : ()=>{}
      onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : ()=>{}
      if(this.status === MyPromise.PENDING){//第二步
        this.resolveCallbacks.push(onFULFILLED);
        this.rejectCallbacks.push(onREJECTED);
      }
      if(this.status === MyPromise.FULFILLED){
        setTimeout(()=>{
          onFULFILLED(this.result)
        })
      }
      if(this.status === MyPromise.REJECTED){
        setTimeout(()=>{
          onREJECTED(this.result)
        })
      }
    
  }
}

坑点:resolve和reject在事件循环末尾执行

上面代码的执行结果是:
image

  • resolve是异步,应该先输出“第四步”,解决:只需要给resolve和reject里面加上setTimeout即可
resolve(result){
    setTimeout(()=>{
      if(this.status === MyPromise.PENDING){
      this.status = this.FULFILLED
      this.result = result
      this.resolveCallbacks.forEach(callback => {callback(result)})
    }
    });
    
  }
  reject(result){
    setTimeout(()=>{
      if(this.status === MyPromise.PENDING){
      this.status = this.REJECTED;
      this.result = result
      this.rejectCallbacks.forEach(callback => {callback(result)})
    }
    })
  }

链式调用

  • then中返回一个新的手写Promise实例
 then(onFULFILLED, onREJECTED){
    return new MyPromise((resolve,reject)=>{
      onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : ()=>{}
      onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : ()=>{}
      if(this.status === MyPromise.PENDING){
        this.resolveCallbacks.push(onFULFILLED);
        this.rejectCallbacks.push(onREJECTED);
      }
      if(this.status === MyPromise.FULFILLED){
        setTimeout(()=>{
          onFULFILLED(this.result)
        })
      }
      if(this.status === MyPromise.REJECTED){
        setTimeout(()=>{
          onREJECTED(this.result)
        })
      }
    })  
  }

完整代码

class MyPromise{
  static PENDING = '待定'; static FULFILLED='成功'; static REJECTED = '失败';
  constructor(func){
    this.status = MyPromise.PENDING;
    this.result = null;
    this.resolveCallbacks = [];
    this.rejectCallbacks = [];
    try{
      func(this.resolve.bind(this), this.reject.bind(this))
    }catch(error){
      this.reject(error)
    }
  }
  resolve(result){
    setTimeout(()=>{
      if(this.status === MyPromise.PENDING){
      this.status = this.FULFILLED
      this.result = result
      this.resolveCallbacks.forEach(callback => {callback(result)})
    }
    });
    
  }
  reject(result){
    setTimeout(()=>{
      if(this.status === MyPromise.PENDING){
      this.status = this.REJECTED;
      this.result = result
      this.rejectCallbacks.forEach(callback => {callback(result)})
    }
    })
    
  }
  then(onFULFILLED, onREJECTED){
    return new MyPromise((resolve,reject)=>{
      onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : ()=>{}
      onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : ()=>{}
      if(this.status === MyPromise.PENDING){
        this.resolveCallbacks.push(onFULFILLED);
        this.rejectCallbacks.push(onREJECTED);
      }
      if(this.status === MyPromise.FULFILLED){
        setTimeout(()=>{
          onFULFILLED(this.result)
        })
      }
      if(this.status === MyPromise.REJECTED){
        setTimeout(()=>{
          onREJECTED(this.result)
        })
      }
    })  
  }
}
posted @ 2025-10-06 17:31  Frommoon  阅读(19)  评论(0)    收藏  举报