手写实现promise,promise.all,race等的实现

一步一步

1、首先来个架子,几大件先摆上,首先是状态三个,方法两个(resolve和reject),then方法。

//弄点变量当作状态,假装很高级的样子
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 开始了
class myPromise{
  constructor(exec){
    //状态初始化为pending
    this.state = PENDING
    //状态resolve变为fulfilled,存储结果
    this.value = ''
    //状态reject后,存储原因
    this.reson = ''
    let resolve = (val) => {
      //状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
      if(this.state == PENDING){
        // 状态变成fulfilled 
        this.state = FULFILLED
        // 将结果记录
        this.value = val
      }
    }
    let reject = (val) => {
      //状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
      if(this.state == PENDING){
        // 状态变成rejected
        this.state = REJECTED
        // 将原因记录
        this.reson = val
      }
    }
    //立即执行exec,放在try catch里面是为了兼容运行出错情况
    try {
      exec(resolve,reject)
    } catch (error) {
      //出错直接reject就行了
      reject(error)
    }
  }
  // 还得有个then方法
  then(onFulfilled, onRejected){

  }
}

2、接下来开始实现then方法

then接受两个参数,一个成功的回调(onFulfilled),一个失败的(onRejected),如果状态是fulfilled,就会执行成功的回调,如果是失败的,就会执行失败的,所以最简单的就是这种:

// 还得有个then方法
  then(onFulfilled, onRejected){
    if(this.state == FULFILLED){
      onFulfilled(this.value)
    }else if(this.state == REJECTED){
      onRejected(this.reson)
    }
  }

一个相当简单的就实现啦。简单测试一下

let p = new myPromise((resolve,reject) => {
  // resolve(111111)
  reject('出错了')
})
p.then(res => {
  console.log(res)
},err => {
  console.log(err)//出错了
})

但是这样会有一个问题,当promise里是异步的时候,是不能返回结果的,如下

let p = new myPromise((resolve,reject) => {
  // resolve(111111)
  // reject('出错了')
  setTimeout(() => {
    resolve('异步执行')
  }, 3000);
})
p.then(res => {
  console.log(res)
},err => {
  console.log(err)
})

此时发现then中并没有成功打印出所希望的res,也就是‘异步执行’这几个字,原因是因为上边实现的then方法执行的时候,此时的promise状态还是pending呢,还没有来得及变化。所以接下来要丰富我们的then方法。

3、支持异步

思路大概是,当执行then的时候,发现现在的状态还是pending的话,就将回调函数存储起来,等真正改变状态,执行resolve或者reject的时候再去执行,所以这里需要需要:

  1. class里声明两个数组,来存储回调函数,这里我命名为resolveList和rejectList
  2. then中判断状态为pending的时候,将回调函数存储起来
  3. 在resovle和reject方法中,执行调用存储的函数

 最后整理的代码如下

//弄点变量当作状态,假装很高级的样子
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 开始了
class myPromise{
  constructor(exec){
    //状态初始化为pending
    this.state = PENDING
    //状态resolve变为fulfilled,存储结果
    this.value = ''
    //状态reject后,存储原因
    this.reson = ''

    //这俩数组存then中的回调函数
    this.resolveList = []
    this.rejectList = []

    let resolve = (val) => {
      //状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
      if(this.state == PENDING){
        // 状态变成fulfilled 
        this.state = FULFILLED
        // 将结果记录
        this.value = val
        // 执行一下可能存在的异步存储的函数
        this.resolveList.forEach(item => {
          item(this.value)
        })
      }
    }
    let reject = (val) => {
      //状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
      if(this.state == PENDING){
        // 状态变成rejected
        this.state = REJECTED
        // 将原因记录
        this.reson = val
        // 执行一下可能存在的异步存储的函数
        this.rejectList.forEach(item => {
          item(this.reson)
        })
      }
    }
    //立即执行exec,放在try catch里面是为了兼容运行出错情况
    try {
      exec(resolve,reject)
    } catch (error) {
      //出错直接reject就行了
      reject(error)
    }
  }
  // 还得有个then方法
  then(onFulfilled, onRejected){
    if(this.state == FULFILLED){
      onFulfilled(this.value)
    }else if(this.state == REJECTED){
      onRejected(this.reson)
    }else if(this.state == PENDING){
      this.resolveList.push(onFulfilled)
      this.rejectList.push(onRejected)
    }
  }
}

let p = new myPromise((resolve,reject) => {
  // resolve(111111)
  // reject('出错了')
  setTimeout(() => {
    resolve('异步执行')
  }, 3000);
})
p.then(res => {
  console.log(res)//成功打印了‘异步执行’
},err => {
  console.log(err)
})

这里有一个可能没什么用的点解释一下,就是为什么要用数组(resolveList和rejectList)去存储,而不用变量去存储,是为了解决下边这种情况

let p = new myPromise((resolve,reject) => {
  // resolve(111111)
  // reject('出错了')
  setTimeout(() => {
    resolve('异步执行')
  }, 3000);
})
p.then(res => {
  console.log(res)
},err => {
  console.log(err)
})

p.then(res => {
  console.log(res+1)
})

这种时候如果用变量的话,第二个的成功的回调就会把第一个成功的回调冲掉,所以要用数组都存储下来。

到这里就大体实现了一个简单的promise,考虑的都是理想情况,比如then里边传的都是函数,没有兼容其他的什么类型。 

下面开始写链式调用

4、链式调用then

首先要明白,链式调用前一个then要返回一个promise才能实现连续的.then,所以我们需要改造一下then方法,让他返回一个promise,并且声明一个处理函数resolvePromise作为集中的对于promise的处理,下边是完整的代码

//弄点变量当作状态,假装很高级的样子
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 开始了
class myPromise{
  constructor(exec){
    //状态初始化为pending
    this.state = PENDING
    //状态resolve变为fulfilled,存储结果
    this.value = ''
    //状态reject后,存储原因
    this.reson = ''

    //这俩数组存then中的回调函数
    this.resolveList = []
    this.rejectList = []

    let resolve = (val) => {
      //状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
      if(this.state == PENDING){
        // 状态变成fulfilled 
        this.state = FULFILLED
        // 将结果记录
        this.value = val
        // 执行一下可能存在的异步存储的函数
        this.resolveList.forEach(item => {
          item(this.value)
        })
      }
    }
    let reject = (val) => {
      //状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
      if(this.state == PENDING){
        // 状态变成rejected
        this.state = REJECTED
        // 将原因记录
        this.reson = val
        // 执行一下可能存在的异步存储的函数
        this.rejectList.forEach(item => {
          item(this.reson)
        })
      }
    }
    //立即执行exec,放在try catch里面是为了兼容运行出错情况
    try {
      exec(resolve,reject)
    } catch (error) {
      //出错直接reject就行了
      reject(error)
    }
  }
  // 还得有个then方法
  then(onFulfilled, onRejected){
    // if(this.state == FULFILLED){
    //   onFulfilled(this.value)
    // }else if(this.state == REJECTED){
    //   onRejected(this.reson)
    // }else if(this.state == PENDING){
    //   this.resolveList.push(onFulfilled)
    //   this.rejectList.push(onRejected)
    // }
    //如果是空或者不是函数,替换成直接返回value或者reson的函数,这样链式的时候如果前边的没有回调函数,也能够将值传递过去
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
    let promise2 = new myPromise((reslove,reject) => {
      if(this.state == FULFILLED){
        setTimeout(() => {
          //异步的,所以用settimeout,而且不用之后使用promise2的时候也会报错
          try {
            //x为then的成功的回调函数返回的结果
            let x = onFulfilled(this.value)
            //resolvePromise为对于promise2的处理
            resolvePromise(promise2,x,reslove,reject)
          } catch (error) {
            reject(error)
          }
        },0)
      }else if(this.state == REJECTED){
        setTimeout(() => {
          try {
            //x为then的失败回调函数返回的结果
            let x = onRejected(this.reson)
            resolvePromise(promise2,x,reslove,reject)
          } catch (error) {
            reject(error)
          }
        },0)
      }else if(this.state == PENDING){
        this.resolveList.push(() => {
          setTimeout(() => {
            try {
              //x为then的成功的回调函数返回的结果
              let x = onFulfilled(this.value)
              resolvePromise(promise2,x,reslove,reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
        this.rejectList.push(() => {
          setTimeout(() => {
            try {
              //x为then的失败回调函数返回的结果
              let x = onRejected(this.reson)
              resolvePromise(promise2,x,reslove,reject)
            } catch (error) {
              reject(error)
            }
          },0)
        })
      }
    })
    return promise2
  }
}

function resolvePromise(promise2,x,resolve,reject){
  if(promise2 === x){
    reject('陷入了死循环')
    return
  }
  //如果是对象或者函数
  if(x !== null && (typeof x === 'object' || typeof x === 'function')){
    let then = x.then
    if(then && typeof then == 'function'){
      // 如果x是个promise,就去执行他的then方法,然后把结果处理出来,当作去往链式调用的结果
      try {
        then.call(x,res => {
          //防止x.then执行出来之后结果还是返回了一个promise,所以递归执行一下resolvePrimise
          resolvePromise(promise2,res,resolve,reject)
        })
      } catch (error) {
        reject(err)
      }
    }else{
      resolve(x)
    }
  }else{
    //如果不是对象,直接resolve
    resolve(x)
  }
}


//自己的测试代码
let p = new myPromise((resolve,reject) => {
  setTimeout(() => {
    resolve('异步执行')
  }, 3000);
})
p.then(res => {
  console.log(res)//异步执行
  return new myPromise((resolve,reject) => {
    setTimeout(()=>{
      resolve(2)
    },3000)
  })
},err => {
  console.log(err)
}).then(res => {
  console.log(res+2) //4
})

p.then(res => {
  console.log(res+1)//异步执行1
})

promise一些方法的实现

1、promise.resolve

myPromise.resolve = (val) => {
//如果是promise的话,直接返回,不是就封装一下
  if(val.then&& typeof val.then == 'function'){
    return val
  }else{
    return new myPromise((resolve,reject) => {
      resolve(val)
    })
  }
}

2、all

myPromise.all = function(arr = []){
  let idx = 0//记录产生了多少个结果
  let len = arr.length//记录数组长度
  let resArr = [] // 存放promise执行的结果
  return new myPromise((resolve,reject) => {
    arr.forEach((item,index) => {
      myPromise.resolve(item).then(res => {
        //保证传入顺序对应结果顺序
        resArr[index] = res
        idx++
        //如果两个值相等的时候,就说明所有的传入的promise都已经执行完毕,可以返回结果了
        if(idx == len){
          resolve(resArr)
        }
      },error => {
        reject(error)
      })
    })
  })
}

3、race

myPromise.race = function(arr = []){
  return new myPromise((resolve,reject) => {
    arr.forEach((item,index) => {
      myPromise.resolve(item).then(res => {
        //谁快直接返回谁就行了
        resolve(res)
      },error => {
        reject(error)
      })
    })
  })
}

就先写这么多,简略的原理实现,有些极端情况并没有考虑,仅供参考,欢迎交流指正~,yeah!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值