手写 Promise

手写 Promise

需要实现的功能

  • 初始化 & 异步调用

    // Promise 的参数是个函数,函数里有两个参数,一个是成功回调,一个是失败回调
    const p1 = new Promise((resolve, reject) => {
      resolve(100)
      // 也支持异步
      // setTimeout(() => {
      //   resolve(100)
      // }, 500)
    })
    
  • then、catch 链式调用

    p.then((data) => {
      return data + 1
    }).then((data) => {
      return data + 2
    }).catch((err) => {
      console.log(err)
    })
    
    // then 也可以传入两个参数
    // 一个是成功后的回调,一个是失败后的回调
    p.then(fn1, fn2)
    
    // 链式调用本质是每次调用返回一个新的 promise
    const p11 = p1.then((data) => {
      return data + 1
    })
    const p12 = p11.then((data) => {
      return data + 2
    })
    const p13 = p12.catch((err) => {
      console.log(err)
    })
    
  • API .resolve .reject .all .race

    // 创建一个 resolved 状态的 promise 并附带成功信息
    const p2 = Promise.resolve(200)
    // 创建一个 rejected 状态的 promise,并附带 rejected 的原因
    const p3 = Promise.reject("错误信息...")
    // 当所有 promise 都 resolved 后返回数组结果。
    // 如果有 rejected 则返回 rejected 状态的 promise 并说明错误原因
    const p4 = Promise.all([p1, p2])
    // 哪个 promise 先执行完就直接返回,不管是 resolved 或 rejected
    const p5 = Promise.race([p1, p2])
    

1. 构造函数

class MyPromise {
  constructor (fn) {
    this.state = 'pending' // 状态,'pending' 'resolved', 'rejected
    this.value = undefined // 成功后的值
    this.reason = undefined // 失败后的原因

    this.resolveCallbacks = []; // pending 状态下,存储成功的回调
    this.rejectCallbacks = []; // pending 状态下,存储失败的回调

    const resolveHandler = (value) => {
      if (this.state === 'pending') {
        this.state = 'resolved'
        this.value = value
        // 状态变化后,执行存储的回调方法
        this.resolveCallbacks.forEach(fn => fn(this.value))
      }
    }
    const rejectHandler = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.rejectCallbacks.forEach(fn => fn(this.reason))
      }
    }
    
    try {
      fn(resolveHandler, rejectHandler)
    } catch (err) {
      rejectHandler(err)
    }
  }

  then(fn1, fn2) {
    // 当 pending 状态下,fn1 fn2 会被存储到 callback 中
  }
    
  // 就是 then 的一个语法糖,简单模式
  catch(fn) {
    return this.then(null, fn)
  }
}

2. then 的链式调用

class MyPromise {
  constructor (fn) {
    this.state = 'pending' // 状态,'pending' 'resolved', 'rejected
    this.value = undefined // 成功后的值
    this.reason = undefined // 失败后的原因

    this.resolveCallbacks = []; // pending 状态下,存储成功的回调
    this.rejectCallbacks = []; // pending 状态下,存储失败的回调

    const resolveHandler = (value) => {
      if (this.state === 'pending') {
        this.state = 'resolved'
        this.value = value
        this.resolveCallbacks.forEach(fn => fn(this.value))
      }
    }
    const rejectHandler = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.resolveCallbacks.forEach(fn => fn(this.reason))
      }
    }

    try {
      fn(resolveHandler, rejectHandler)
    } catch (error) {
      rejectHandler(err)
    }
  }

  then(fn1, fn2) {
    // 当 pending 状态下,fn1 fn2 会被存储到 callback 中
    fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
    fn2 = typeof fn2 === 'function' ? fn2 : (v) => v

    if (this.state === 'pending') {
      return new MyPromise((resolve, reject) => {
        // push 进去的函数得等状态为 resolved 的时候才会被执行
        this.resolveCallbacks.push(() => { 
          try {
            const newValue = fn1(this.value);
            resolve(newValue)
          } catch (err) {
            reject(err)
          }
         })

        // push 进去的函数得等状态为 rejected 的时候才会被执行
        this.resolveCallbacks.push(() => { 
          try {
            const newReason = fn2(this.reason);
            reject(newReason )
          } catch (err) {
            reject(err)
          }
         })
      })
    }

    // const p11 = p1.then((data) => {
    //   return data + 1
    // })
    if (this.state === 'resolved') {
      return new MyPromise((resolve, reject) => {
        try {
          // 传入 resolved 的返回值
          const newValue = fn1(this.value)
          resolve(newValue)
        } catch (error) {
          reject(error)
        }
      })
    }

    if (this.state === 'rejected') {
      return new MyPromise((resolve, reject) => {
        try {
          // 传入 rejected 的原因
          const newReason = fn2(this.reason)
          reject(newReason)
        } catch (error) {
          reject(error)
        }
      })
    }
  }
    
  // 就是 then 的一个语法糖,简单模式
  catch(fn) {
    return this.then(null, fn)
  }
}

3. Promise-all 和 race

class MyPromise {
  constructor (fn) {
    this.state = 'pending' // 状态,'pending' 'resolved', 'rejected
    this.value = undefined // 成功后的值
    this.reason = undefined // 失败后的原因

    this.resolveCallbacks = []; // pending 状态下,存储成功的回调
    this.rejectCallbacks = []; // pending 状态下,存储失败的回调

    const resolveHandler = (value) => {
      if (this.state === 'pending') {
        this.state = 'resolved'
        this.value = value
        this.resolveCallbacks.forEach(fn => fn(this.value))
      }
    }
    const rejectHandler = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.resolveCallbacks.forEach(fn => fn(this.reason))
      }
    }

    try {
      fn(resolveHandler, rejectHandler)
    } catch (error) {
      rejectHandler(error)
    }
  }

  then(fn1, fn2) {
    // 当 pending 状态下,fn1 fn2 会被存储到 callback 中
    fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
    fn2 = typeof fn2 === 'function' ? fn2 : (v) => v

    if (this.state === 'pending') {
      return new MyPromise((resolve, reject) => {
        // push 进去的函数得等状态为 resolved 的时候才会被执行
        this.resolveCallbacks.push(() => { 
          try {
            const newValue = fn1(this.value);
            resolve(newValue)
          } catch (error) {
            reject(error)
          }
         })

        // push 进去的函数得等状态为 rejected 的时候才会被执行
        this.resolveCallbacks.push(() => { 
          try {
            const newReason = fn2(this.reason);
            reject(newReason)
          } catch (error) {
            reject(error)
          }
         })
      })
    }

    // const p11 = p1.then((data) => {
    //   return data + 1
    // })
    if (this.state === 'resolved') {
      return new MyPromise((resolve, reject) => {
        try {
          // 传入 resolved 的返回值
          const newValue = fn1(this.value)
          resolve(newValue)
        } catch (error) {
          reject(error)
        }
      })
    }

    if (this.state === 'rejected') {
      return new MyPromise((resolve, reject) => {
        try {
          // 传入 rejected 的原因
          const newReason = fn2(this.reason)
          reject(newReason)
        } catch (error) {
          reject(error)
        }
      })
    }
  }
    
  // 就是 then 的一个语法糖,简单模式
  catch(fn) {
    return this.then(null, fn)
  }
}

// 全局静态 API
MyPromise.resolve = function(value) {
  return new MyPromise((resolve, reject) => resolve(value))
}

MyPromise.reject = function(reason) {
  return new MyPromise((resolve, reject) => reject(reason))
}

MyPromise.all = function (promiseList = []) {
  const p1 = new MyPromise((resolve, reject) => {
    const result = [] // 存储 promiseList 所有的结果
    const length = promiseList.length
    
    let resolvedCount = 0
    promiseList.forEach((p) => {
      p.then(data => {
        result.push(data)
        // resolvedCount 必须在 then 里面做 ++ (then 执行,累加才算数)
        // 不能用 index,因为 promise 里是异步的,index 递增是同步的
        resolvedCount++
        if (resolvedCount === length) {
          // 已经遍历到了最后一个 promise,把数据 resolve 出去
          resolve(result)
        }
      }).catch(err => {
        reject(err)
      })
    })
  })
  return p1
}

MyPromise.race = function (promiseList = []) {
  let resolved = false
  const p1 = new MyPromise((resolve, reject) => {
    promiseList.forEach(p => {
      p.then(data => {
        if (!resolved) {
          resolve(data)
          resolved = true
        }
      }).catch((err) => {
        reject(err)
      })
    })
  })
  return p1
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值