从里到外看透Promise

本篇文章将从零手写一个Promise,实现Promise的then , catch 实例方法;和all,allSettled,等静态方法。如有疑问或其他问题欢迎留言指教。

首先我们来实现一个裸的,简易版Promise,请看下文

class MyPromise {
	state = 'pending' // 定义promise 的状态 pending | fulfilled | rejected
	resolveCallbacks = [] // .then 订阅的方法会放在这里面,等待resolve后执行

	constructor(fn) {
		// fn 是实例promise 时传入的函数
		// resolve 的回调, 传入 value = 1
		const resolveHandler = (value) => {
			if(this.state === 'pending') {
				this.state = 'fulfilled'
				this.value = value
				this.resolveCallbacks.forEach(fn => fn())
			}
		}
		// reject 的回调
		const rejectHandler = () => {}
		// 避免传入的fn运行时候报错,使用try{} catch{} 包裹
		try{
			fn(resolveHandler, rejectHandler)
		}catch(error){
		}
	}
	then(fn) {
		// fn 对应p1.then() 里面传入的函数
		if(this.state === 'pending') {
			// 把函数放入resolveCallbacks 数组,等待2s钟后resolve 执行时候调用
			this.resolveCallbacks.push(() => {
				// 	2s钟后调用,this.value 就会是 resolve(1) -- 1 这个值
				fn(this.value)
			})
		}
	}
}

const p1 = new MyPromise((resolve, reject) => {
	setTimeout(() => {
		resolve(1)
	}, 2000)
})

p1.then(res => {
	console.log(res) // 2s 后,1 就被打印出来了
})
  • 简单的实现后会发现有几点问题
  • 问题1: .then() 方法传入的是两个函数,传入两个函数该怎么实现呢?
  • 问题2: .then 方法只执行了一种状态,=== pending 的时候,那么 等于其他两个状态的时候又是怎样的逻辑呢?
  • 问题3: .then() 返回的是一个链式调用,还能继续执行.then 或者 .catch 方法。这样的实现又是怎么的过程?
  • 带着这三个问题,我们再来更改一下以上的代码实现
class MyPromise {
    // 定义promise 的状态 pending | fulfilled | rejected
    state = 'pending' 
    // 接收resolve 的值
    value = undefined 
    // 接收reject 的值
    error = undefined
    // .then 订阅的方法会放在这里面,等待resolve后执行
    resolveCallbacks = [] 
    // .catch 订阅的方法会放在这里面,等待reject后执行
    rejectCallbacks = [] 

    // fn 是实例promise 时传入的函数
    constructor(fn) {
      // resolve 的回调, 传入 value = 1
      const resolveHandler = (value) => {
        if(this.state === 'pending') {
          this.state = 'fulfilled'
          this.value = value
          this.resolveCallbacks.forEach(fn => fn())
        }
      }
      // reject 的回调
      const rejectHandler = (e) => {
        if(this.state === 'pending') {
          this.state = 'reject'
          this.error = e
          this.rejectCallbacks.forEach(fn => fn())
        }
      }
      // 避免传入的fn运行时候报错,使用try{} catch{} 包裹
      try{
        fn(resolveHandler, rejectHandler)
      }catch(error){
      	// 函数报错,执行reject
        rejectHandler(error)
      }
    }
    // fn, fn2 对应p1.then() 里面传入的函数
    then(fn1, fn2) {
      // 首先判断fn1 和 fn2 是否是传入的函数
      fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
      fn2 = typeof fn2 === 'function' ? fn2 : (v) => v
      
      if(this.state === 'pending') {
        // 把函数放入resolveCallbacks 数组,等待2s钟后resolve 执行时候调用
        return new MyPromise((resolve, reject) => {
          this.resolveCallbacks.push(() => {
            // 	2s钟后调用,this.value 就会是 resolve(1) -- 1 这个值
            try {
              const res = fn1(this.value)
              resolve(res || this.value)
            }catch(err) {
              console.log(err)
              reject(err)
            }
          })

          // reject 存入数据,等待调用
          this.rejectCallbacks.push(() => {
            try {
              const res = fn2(this.error)
              reject(res || this.error)
            } catch (error) {
              reject(error)
            }
          })
        })
      }

      // 执行的是resolve 的同步状态
      if(this.state === 'fulfilled') {
        return new MyPromise((resolve, reject) => {
          // 处理函数有返回值
          try {
            const res = fn1(this.error)
            reject(res || this.error)
          } catch (err) {
            reject(err)
          }
        })
      }
      // 执行的是reject 的同步状态
      if(this.state === 'rejected') {
        return new MyPromise((resolve, reject) => {
          // 处理函数有返回值
          try {
            const res = fn2(this.error)
            reject(res || this.error)	
          } catch (err) {
            reject(err)
          }
        })
      }
    }
    // catch 相当于then的语法糖,直接调用.then 
    catch (fn) {
      return this.then(null, fn) 
    }
 }
const p1 = new MyPromise((resolve, reject) => {
	setTimeout(() => {
		resolve(1)
	}, 2000)
})
// 传入两个参数
p1.then(res => {
	console.log(res) // 2s 后,1 就被打印出来了
}, err => console.log(err))

const p2 = new MyPromise((resolve, reject) => {
	resolve(1)
})

至此,我们上面提出的问题也全部解决,Promise 的 then 和 catch 方法就实现完成了。到这里我们的工作还没有结束,promise 除了能使用new Promise() 调用外还能 Promise.reslove() 来执行函数,这些函数就是Promise上面的静态方法。话不多说,上代码

Promise.resolve()

class MyPromise {
   ...
   static resolve (value) {
    return new MyPromise((resolve, reject) => {
       resolve(value)
     })
   }
   ...
}
  • Promise.reject() 同理

Promise.all()

 class MyPromise {
	...
	static all(list) {
      const p = new MyPromise((resolve, reject) => {
        const res = []
        // 遍历里面所有的方法        
        list.forEach(p => {
          p.then(d => {
            res.push(d)
            if(list.length === res.length) {
              resolve(res)
            }
          }).catch(err => {
          	// 	有一个失败,返回失败
            reject(err)
          })
        })
      }) 
      // 返回一个Promise 对象
      return p
    }
	...
}

Promise.allSettled()

...
 static allSettled (list) {
   const p = new MyPromise((resolve)  => {
   	// 成功和失败的结果都放入数组
     let result = []
     list.forEach(fn => {
       fn.then(res => {
         result.push({status: 'fulfilled', value: res})
         // 所有方法都返回后,执行resolve
         if(result.length === list.length) {
           resolve(result)
         }
       }).catch(err => {
         result.push({status: 'rejected', reason: err})
         // 所有方法都返回后,执行resolve
         if(result.length === list.length) {
           resolve(result)
         }
       })
     })
   })
   return p
 }
...

Promise.race()

static race (list) {
  const p = new MyPromise((resolve, reject) => {
  	// 判断是否有promise 已经 返回(不管是错误返回还是正确返回)
    let bool = false
    list.forEach(fn => {
      fn.then(res => {
      	// 只返回第一次的promise
        if(!bool) {
          resolve(res)
          bool = true
        }
      }).catch(err => {
      	// 只返回第一次的promise
        if(!bool) {
          console.log(err,'err');
          resolve(err)
          bool = true
        }
      })
    })
  })
  return p
}
  • 完整代码如下
class MyPromise {
    // 定义promise 的状态 pending | fulfilled | rejected
    state = 'pending' 
    // 接收resolve 的值
    value = undefined 
    // 接收reject 的值
    error = undefined
    // .then 订阅的方法会放在这里面,等待resolve后执行
    resolveCallbacks = [] 
    // .catch 订阅的方法会放在这里面,等待reject后执行
    rejectCallbacks = [] 
    // fn 是实例promise 时传入的函数
    constructor(fn) {
      // resolve 的回调, 传入 value = 1
      const resolveHandler = (value) => {
        if(this.state === 'pending') {
          this.state = 'fulfilled'
          this.value = value
          this.resolveCallbacks.forEach(fn => fn())
        }
      }
      // reject 的回调
      const rejectHandler = (e) => {
        if(this.state === 'pending') {
          this.state = 'reject'
          this.error = e
          this.rejectCallbacks.forEach(fn => fn())
        }
      }
      // 避免传入的fn运行时候报错,使用try{} catch{} 包裹
      try{
        fn(resolveHandler, rejectHandler)
      }catch(error){
        rejectHandler(error)
      }
    }
    // fn, fn2 对应p1.then() 里面传入的函数
    then(fn1, fn2) {
      // 首先判断fn1 和 fn2 是否是传入的函数
      fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
      fn2 = typeof fn2 === 'function' ? fn2 : (v) => v
      if(this.state === 'pending') {
        // 把函数放入resolveCallbacks 数组,等待2s钟后resolve 执行时候调用
        return new MyPromise((resolve, reject) => {
          this.resolveCallbacks.push(() => {
            // 	2s钟后调用,this.value 就会是 resolve(1) -- 1 这个值
            try {
              const res = fn1(this.value)
              resolve(res || this.value)
            }catch(err) {
              console.log(err)
              reject(err)
            }
          })

          // reject 存入数据,等待调用
          this.rejectCallbacks.push(() => {
            try {
              const res = fn2(this.error)
              reject(res || this.error)
            } catch (error) {
              reject(error)
            }
          })
        })
        
      }

      // 执行的是resolve 的同步状态
      if(this.state === 'fulfilled') {
        return new MyPromise((resolve, reject) => {
          // 处理函数有返回值
          try {
            const res = fn1(this.error)
            reject(res || this.error)
          } catch (err) {
            reject(err)
          }
        })
      }
      // 执行的是reject 的同步状态
      if(this.state === 'rejected') {
        return new MyPromise((resolve, reject) => {
          // 处理函数有返回值
          try {
            const res = fn2(this.error)
            reject(res || this.error)	
          } catch (err) {
            reject(err)
          }
        })
      }
    }
    // catch 相当于then的语法糖,直接调用.then 
    catch (fn) {
      return this.then(null, fn) 
    }

    // 静态resolve 方法
    static resolve (value) {
      return new MyPromise((resolve, reject) => {
        resolve(value)
      })
    }

    /** all 方法,全部成功就是成功 */
    static all(list) {
      const p = new MyPromise((resolve, reject) => {
        const res = []
        // 遍历里面所有的方法        
        list.forEach(p => {
          p.then(d => {
            res.push(d)
            if(list.length === res.length) {
              resolve(res)
            }
          }).catch(err => {
            reject(err)
          })
        })
      }) 
      return p
    }

    /** allSettled 成功或者失败都会返回 */
    static allSettled (list) {
      const p = new MyPromise((resolve)  => {
        let result = []
        list.forEach(fn => {
          fn.then(res => {
            result.push({status: 'fulfilled', value: res})
            if(result.length === list.length) {
              resolve(result)
            }
          }).catch(err => {
            result.push({status: 'rejected', reason: err})
            if(result.length === list.length) {
              resolve(result)
            }
          })
        })
      })
      return p
    }

    /** race 谁先返回,就直接返回 */
    static race (list) {
      const p = new MyPromise((resolve, reject) => {
        let bool = false
        list.forEach(fn => {
          fn.then(res => {
            if(!bool) {
              resolve(res)
              bool = true
            }
          }).catch(err => {
            if(!bool) {
              console.log(err,'err');
              resolve(err)
              bool = true
            }
          })
        })
      })
      return p
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值