手写promise——Ts,实现then;catch;all这3个常用方法 (步骤详细)

1.首先定义一个类MyPromise以及声明一些关键的参数类型

MyPromise 这个类里应该包含

属性

  1. status状态;
  2. callbacks 用于存放then、catch传入的方法
  3. result 用于保存结果

方法

  1. resolve 成功回调函数
  2. reject 错误回调函数
/**
*	定义泛型
*/
type MyPromiseType = InstanceType<typeof MyPromise>
type GetKeyType<T,K extends keyof T> = T[K]
type Resolve = GetKeyType<MyPromiseType, 'resolve'>
type Reject = GetKeyType<MyPromiseType, 'reject'>

class MyPromise {
    
    
  [key:string]: any
  status: 'resolved' | 'rejected' | 'pending' = 'pending'
  callbacks: any[] = []
  result:any = null
  constructor(fn:(_:Resolve,__:Reject) => void) {
    
    
  	/**
  	* 绑定函数this指向
  	*/
    this.initBind()
    /**
    * 初始化值
    */
    this.initValue()
    
    fn(this.resolve, this.reject)
  }
  
   initValue() {
    
    
    this.status = 'pending'
    this.callbacks = []
    this.result = null
  }
  
  initBind () {
    
    
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }

   resolve(data:any) {
    
    
    if (this.status !== 'pending') return
    this.status = 'resolved'
    this.result = data
    try {
    
    
  }

  reject(data:any) {
    
    
    if (this.status !== 'pending') return
    this.status = 'rejected'
    this.result = data
 }

}

promise状态一旦发生改变,是不可逆的,我们需要在resolve、reject这个方法里面添加
if (this.status !== ‘pending’) return 防止promise状态发生二次改变

ps:如果对ts有兴趣可以点击下面可链接

TS进阶

2. 实现then

then实现的功能

  1. 接受两个回调函数,一个成功,一个失败
  2. 储存回调函数,在调用resolve或者reject方法时再调用对应的函数(及callbacks里的方法)
  3. 能够链式调用,比如new MyPromise.then(callback).catch(callback)
MyPromise.prototype.then = function(success:Function, onRejected:Function) {
    
    
  if (this.status === 'pending') {
    
    
    this.callbacks.push({
    
    success,error})
  } else if (this.status === 'resolved') {
    
    
    setTimeout(() => {
    
    
      success(this.result)
    })
  } else if (this.status === 'rejected') {
    
    
    onRejected(this.result)
  }
  return this
}

实现思路

  1. 根据状态status判断是将方法存起来还是立即调用;
  2. setTimeout代替微任务,保证能获取到this.result;
  3. return this 保证能链式调用;

3. 实现catch

catch实现的功能

  1. catch接受一个回调函数
  2. then中的回调执行错误时会执行catch的回调
// 实现catch
MyPromise.prototype.catch = function (onRejected:Function) {
    
     //.catch接受一个回调函数
  if (this.status === 'pending') {
    
    
      // 将回调函数放入callbacks数组中
      this.callbacks.push({
    
     onRejected })
  } else if (this.status === 'rejected') {
    
    
    setTimeout(() => {
    
    
        onRejected(this.result)
    })
  }
}

这两个方法实现了还暂时不能使用,需要在MyPromise这个类中的对应方法,加入如下代码

  resolve(data:any) {
    
    
    if (this.status !== 'pending') return
    this.status = 'resolved'
    this.result = data
    try {
    
    
      this.callbacks.forEach(val => {
    
    
        val.success && val.success(this.result)
      })
    } catch (error) {
    
    
      this.callbacks.forEach(val => {
    
    
        val.onRejected && val.onRejected(error)
      })
    }
  }

  reject(data:any) {
    
    
    if (this.status !== 'pending') return
    this.status = 'rejected'
    this.result = data
    this.callbacks.forEach(val => {
    
    
      val.onRejected && val.onRejected(this.result)
    })
  }

实现思路

  1. 使用new MyPromise这个方法中,用户主动调用resolve时,检测是否有在then中存入的方法;
  2. 由于callbacks这个数组不止装了then的方法,执行时我们需要执行对用的方法
  3. then的回调函数中,如果出现错误代码,就会执行catch的回调函数;

4. 实现all

all 实现的功能

  1. 接收一个Promise数组
  2. 当这个数组所有promise都返回resolve,Rromise.all返回一个resolve, 返回的是一个数组,这个数组中的值与promise数组一 一对应的;
  3. 或当其中一个promise返回reject,那么Rromise.all立即中断后面的执行,立即返回reject
 MyPromise.all = function(list:any[]) {
    
    
  return new MyPromise((resolve, reject) => {
    
    
    const allList = list.filter(val => val instanceof MyPromise)
    const resultList:any[] = Array.from({
    
    length: allList.length})
    allList.forEach((val, idx) => {
    
    
      val
        .then((result:any) => {
    
    
          resultList.splice(idx, 1, result)
          resultList.filter(item => item).length === allList.length && resolve(resultList)
        })
        .catch((err:any) => {
    
    
          reject(err)
        })
    })
  })
}

最后放上完整代码(包括使用示例)

type MyPromiseType = InstanceType<typeof MyPromise>
type GetKeyType<T,K extends keyof T> = T[K]
type Resolve = GetKeyType<MyPromiseType, 'resolve'>
type Reject = GetKeyType<MyPromiseType, 'reject'>

class MyPromise {
    
    
  [key:string]: any
  status: 'resolved' | 'rejected' | 'pending' = 'pending'
  callbacks: any[] = []
  result:any = null
  constructor(fn:(_:Resolve,__:Reject) => void) {
    
    
    this.initBind()
    this.initValue()
    fn(this.resolve, this.reject)
  }

  initValue() {
    
    
    this.status = 'pending'
    this.callbacks = []
    this.result = null
  }

  initBind () {
    
    
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }

  resolve(data:any) {
    
    
    if (this.status !== 'pending') return
    this.status = 'resolved'
    this.result = data
    try {
    
    
      this.callbacks.forEach(val => {
    
    
        val.success && val.success(this.result)
      })
    } catch (error) {
    
    
      this.callbacks.forEach(val => {
    
    
        val.onRejected && val.onRejected(error)
      })
    }
  }

  reject(data:any) {
    
    
    if (this.status !== 'pending') return
    this.status = 'rejected'
    this.result = data
    this.callbacks.forEach(val => {
    
    
      val.onRejected && val.onRejected(this.result)
    })
  }
}

// 实现then
MyPromise.prototype.then = function(success:Function, onRejected:Function) {
    
    
  if (this.status === 'pending') {
    
    
    this.callbacks.push({
    
    success,onRejected})
  } else if (this.status === 'resolved') {
    
    
    setTimeout(() => {
    
    
      success(this.result)
    })
  } else if (this.status === 'rejected') {
    
    
    onRejected(this.result)
  }
  return this
}


// 实现catch
MyPromise.prototype.catch = function (onRejected:Function) {
    
     //.catch接受一个回调函数
  if (this.status === 'pending') {
    
    
      // 将回调函数放入callbacks数组中
      this.callbacks.push({
    
     onRejected })
  } else if (this.status === 'rejected') {
    
    
    setTimeout(() => {
    
    
        onRejected(this.result)
    })
  }
}

//实现all
// @ts-ignore
 MyPromise.all = function(list:any[]) {
    
    
  return new MyPromise((resolve, reject) => {
    
    
    const allList = list.filter(val => val instanceof MyPromise)
    const resultList:any[] = Array.from({
    
    length: allList.length})
    allList.forEach((val, idx) => {
    
    
      val
        .then((result:any) => {
    
    
          resultList.splice(idx, 1, result)
          resultList.filter(item => item).length === allList.length && resolve(resultList)
        })
        .catch((err:any) => {
    
    
          reject(err)
        })
    })
  })
}


// new MyPromise((resolve:any, reject:any) => {
    
    
//   const num = 1
//   setTimeout(() => {
    
    
//     if (num % 2) {
    
    
//       resolve({msg: "成功"})
//     } else {
    
    
//       reject({msg: "成功"})
//     }
//   }, 2000);
// }).then(() => {
    
    
//   throw Error('124')
// }).catch((err:any) => {
    
    
//   console.log(err);
// })


// const fn1 = () => {
    
    
//   return test1
// }

// (async() => {
    
    
//   const result = await fn1()
//   console.log(result);
// })()

const v1 = new MyPromise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
      resolve({
    
    msg: "成功1"})
  }, 5000);
})
const v2 = new MyPromise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
      // resolve({msg: "成功2"})
      reject({
    
    msg: "失败2"})
  }, 4000);
})
const v3 = new MyPromise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
      resolve({
    
    msg: "成功3"})
  }, 1000);
})

// @ts-ignore
MyPromise.all([v1,v2,v3]).then(res => {
    
    
  console.log(res);
}).catch((err:any) => {
    
    
  console.log(err);
})

猜你喜欢

转载自blog.csdn.net/weixin_44441196/article/details/127324837