手把手教你如何手写Promise

62 阅读3分钟

想要知道如何手写Promise,首先我们需要清楚Promise有哪些优点,以及它解决了什么问题,Promise都有哪些方法和属性,这些方法和属性是如何实现的,我们都知道promise主要是为了解决异步调用,地域回调的问题,我们都知道,promise有3个状态,分别是pengding(创建promise的默认状态),fullfilled(成功后的状态),rejected(失败的状态),以及promise有.then()方法,并且可以链式调用,有.resolve()以及.reject()方法.一下是用代码展示:

const p= new Promise(()=>{})
p.then(()=>{},()=>{})
const p1=Promise.resolve()
const p2=Promise.reject()

如果我们要手写一个Promise,从上面的代码中,我们可以梳理出一个思路: 1.new Promise,证明Promise是一个类,我们在new Promise的时候,必须要传一个处理函数,构造函数有一个函数形参,并且需要立即调用执行 2.promise的默认状态是pending,所以有个state属性,默认值是penging 3.promise类里面有resolve,.reject,以及then方法, 这个时候我们就可以构建出一个大致的结构;

class MyPromise{
    state:"pending",//promise状态变量,默认pending
    construct(fn:function){
        if(typeof fn!=='function'){
        throw new Error('new Promise()初始化必须传入一个函数');//如果传入的不是一个函数给出提示
        }
        fn()//立即调用
    }
    resolve(){}
    reject(){}
    then(){}
}

这样promise类的大致结构就形成了,接下来我们来分析一下,每个方法都有哪些特征,以及每个方法都做了什么事情, 我们先来看看then方法吧,我们先看代码p.then(()=>{},()=>{}), 1.我们可以看到then方法中有2个函数形参,当然可传也可以不传,当执行成功的时候,执行的是resolve方法,失败的时候是reject方法 2.又因为then是可以链式调用的,最后返回的也是一个promise,所以我们接着填充上面的代码:

class MyPromise{
    callbacks:any[]//其实是一个二维数据
    state:"pending",//promise状态变量,默认pending
    construct(fn:function){
        if(typeof fn!=='function'){
        throw new Error('new Promise()初始化必须传入一个函数');//如果传入的不是一个函数给出提示
        }
        fn(this.resolve.bind(this), this.reject.bind(this))//立即调用并改变this指向
    }
    resolve(result){
        setTimeout(()=>{
          if (this.state !== 'pending') return;
          this.state = 'fulfilled';
          this.callbacks.forEach((handle) => {
        if (typeof handle[0] === 'function') {
          handle[0].call(undefined, result);//result 默认传递的第一个参数
        }
      });
        },0)
    }
    reject(reason){
     setTimeout(() => {
      if (this.state !== 'pending') return;
      this.state = 'rejected';
      this.callbacks.forEach((handle) => {
        if (typeof handle[1] === 'function') {
           handle[1].call(undefined, reason)
        }
      });
    }, 0);
    }
    then(succeed?, fail?){
        const handle: any[] = [];
        if (typeof succeed === 'function') {
          handle[0] = succeed;
        }
        if (typeof fail === 'function') {
          handle[1] = fail;
        }
        handle[2] = new Promise1(() => {});
        this.callbacks.push(handle);
        return handle[2];//返回一个promise
    }
}

这样一个简单的promise就完成了,如果想要更加的话,可以增加以下代码:

class MyPromise{
    callbacks:any[]//其实是一个二维数据
    state:"pending",//promise状态变量,默认pending
    construct(fn:function){
        if(typeof fn!=='function'){
        throw new Error('new Promise()初始化必须传入一个函数');//如果传入的不是一个函数给出提示
        }
        fn(this.resolve.bind(this), this.reject.bind(this))//立即调用并改变this指向
    }
   resolve(result) {
    setTimeout(() => {
      if (this.state !== 'pending') return;
      this.state = 'fulfilled';
      this.callbacks.forEach((handle) => {
        if (typeof handle[0] === 'function') {
          const x = handle[0].call(undefined, result);
          handle[2].resolveWith(x, result);
        }
      });
    }, 0);
  }
  reject(reason) {
    setTimeout(() => {
      if (this.state !== 'pending') return;
      this.state = 'reject';
      this.callbacks.forEach((handle) => {
        if (typeof handle[1] === 'function') {
          const x = handle[1].call(undefined, reason);
          handle[2].resolveWith(x, reason);
        }
      });
    }, 0);
  }

  then(succeed?, fail?) {
    const handle: any[] = [];
    if (typeof succeed === 'function') {
      handle[0] = succeed;
    }
    if (typeof fail === 'function') {
      handle[1] = fail;
    }
    handle[2] = new Promise1(() => {});
    this.callbacks.push(handle);
    return handle[2];
  }

  resolveWith(x) {
    if (this === x) {
      return this.reject(new TypeError('cannot resolve'));
    }
    if (x instanceof Promise1) {
      x.then(
        (result) => {
          this.resolve(result);
        },
        (reason) => {
          this.reject(reason);
        }
      );
    }
    if (x instanceof Object) {
      let then;
      try {
        then = x.then;
      } catch (err) {
        this.reject(err);
      }
      if (typeof then === 'function') {
        try {
          then.call(
            x,
            (y) => {
              this.resolveWith(y);
            },
            (r) => {
              this.reject(r);
            }
          );
        } catch (e) {
          this.reject(e);
        }
      } else {
        this.resolve(x);
      }
    } else {
      this.resolve(x);
    }
  }
}

OK,到这里我们就手写了一个比较OK的Promise啦!当然这个代码是可以优化和精简的,我只是为了能够让大家看到promise的每个构建步骤,就没有进行代码优化,有兴趣的小伙伴可以继续完善呀!