手写Promise

196 阅读4分钟

写在前面

参考了其他promise文章,这里记录一下自己的理解

promiseA+ 规范

  1. promise有三种状态 pendingfulfilledrejected,分别代表等待中,成功,失败,而且状态只能更改一次,new实例后初始化pending
  2. then返回一个新的Promise,支持链式操作

正文

知道规范后我们先来简单版本,然后一点点补齐内容

基础版

class myPromise {
  constructor(fn) {
    this.status = 'PENDING'
    this.value = undefined  // resolve的值
    this.reason = undefined // reject的值

    this.onFulfilledCallbacks = []  // 成功态回调函数队列
    this.onRejectedCallbacks = []  // 失败态回调函数队列

    const resolve = value => {
      if (this.status !== 'PENDING') return
      this.status = 'FULFILLED'
      this.value = value
      // 如果 resolve 是同步的话  这个回调是空的
      this.onFulfilledCallbacks.forEach(fn => fn())
    }

    const reject = reason => {
      if (this.status !== 'PENDING') return
      this.status = 'REJECTED'
      this.reason = reason
      this.onRejectedCallbacks.forEach(fn => fn())
    }

    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }

  then(onFulfilled, onRejected) {
    switch (this.status) {
      case 'PENDING':
        // 因为异步 所以一直处于padding转态
        this.onFulfilledCallbacks.push(() => onFulfilled(this.value))
        this.onRejectedCallbacks.push(() => onRejected(this.reason))
        break;

      /**
       * 如果 resolve 是同步的话 就会执行下面的
       * 当处于异步的时候then已经调用过了 即使
       * status的状态改变了 也不会执行
       */
      case 'FULFILLED':
        onFulfilled(this.value)
        break;

      case 'REJECTED':
        onRejected(this.reason)
        break;

    }
  }
}

new MyPromise((resolve, reject) => {
  console.log(111)
  resolve(1)
  // setTimeout(() => resolve(1), 1000)
  console.log(222)
}).then(res => {
  console.log(res, 'res') 
}, rej => {
  console.log(rej, 'rej')
})

then的链式调用

  then(onFulfilled, onRejected) {
    return new myPromise((resolve, reject) => {
      let x = null
      switch (this.status) {
        case 'PENDING':
          // 因为异步 所以一直处于padding转态
          this.onFulfilledCallbacks.push(() => {
            x = onFulfilled(this.value)
            resolve(x)
          })
          this.onRejectedCallbacks.push(() => {
            x=onRejected(this.reason)
            reject(x)
          })
          break;

        /**
         * 如果 resolve 是同步的话 就会执行下面的
         * 当处于异步的时候then已经调用了 即使
         * status的状态改变了 也不会执行
         */
        case 'FULFILLED':
          x = onFulfilled(this.value)
          resolve(x)
          break;

        case 'REJECTED':
          x = onRejected(this.reason)
          reject(x)
          break;

      }
    })
  }
  
  new myPromise((resolve, reject) => {
  console.log(333)
  // resolve(1)
  setTimeout(() => resolve(1), 1000)
  console.log(222)
}).then(res => {
  console.log(res)
  return 6
}).then(res => {
  console.log(res, 'res')
})

如果说then里面返回一个promise怎么办,这时我们需要封装一下

 then(onFulfilled, onRejected) {
    let newPromise = new myPromise((resolve, reject) => {
      let x = null
      switch (this.status) {
        case 'PENDING':
          // 因为异步 所以一直处于padding转态
          this.onFulfilledCallbacks.push(() => {
            x = onFulfilled(this.value)
            this.resolvePromise(newPromise, x, resolve, reject)

          })
          this.onRejectedCallbacks.push(() => {
            x = onRejected(this.reason)
            this.resolvePromise(newPromise, x, resolve, reject)

          })
          break;

        /**
         * 如果 resolve 是同步的话 就会执行下面的
         * 当处于异步的时候then已经调用了 即使
         * status的状态改变了 也不会执行
         */
        case 'FULFILLED':
          x = onFulfilled(this.value)
          this.resolvePromise(newPromise, x, resolve, reject)

          break;

        case 'REJECTED':
          x = onRejected(this.reason)
          this.resolvePromise(newPromise, x, resolve, reject)

          break;
      }
    })

    return newPromise
  }

  // 如果返回promise做相应处理 否则直接return 值
  resolvePromise(promise, x, resolve, reject) {
    if (promise === x) return reject(new TypeError('promise是同一个'))
    // 判断 x 是不是promise
    if (typeof x === 'object' && x != null || typeof x === 'function') {
      try {
        if (typeof x.then === 'function') {
          x.then(res => {
            this.resolvePromise(promise, res, resolve, reject)
          }, err => {
            reject(err)
          })
          return
        }
        resolve(x)
      } catch (err) {
        reject(err)
      }
    } else {
      // 如果不是直接调用resolve
      resolve(x)
    }
  }
  
  new myPromise((resolve, reject) => {
  console.log(333)
  // resolve(1)
  setTimeout(() => resolve(1), 1000)
  console.log(222)
}).then(res => {
  return new myPromise((resolve, reject) => {
    console.log(2, res)
    resolve({
      name: "第2个传递的值"
    })
  })
})
  .then(res => {
    return new myPromise((resolve, reject) => {
      console.log(3, res)
      resolve(new myPromise((resolve, reject) => {
        console.log(3, res)
        resolve({
          name: "第3个传递的值"
        })
      }))
    })
  })
  .then(res => {
    console.log(res, '555')
  })

all

  all(lists) {
    let resArr = [] //存储处理结果的数组
    let index = 0
    return new myPromise((resolve, reject) => {
      for (let i = 0; i < lists.length; i++) {
        lists[i].then(res => {
          resArr[i] = res
          index++
          if (index === lists.length) {
            resolve(resArr)
          }
        }).catch(err => {
          reject(err)
          return
        })
      }

    })
  }

catch

catch(onReJected) {
    return this.then(undefined, onReJected)
}

完整代码

class myPromise {
  constructor(fn) {
    this.status = 'PENDING'
    this.value = undefined  // resolve的值
    this.reason = undefined // reject的值

    this.onFulfilledCallbacks = []  // 成功态回调函数队列
    this.onRejectedCallbacks = []  // 失败态回调函数队列


    const resolve = value => {
      if (this.status !== 'PENDING') return
      this.status = 'FULFILLED'
      this.value = value
      // 如果 resolve 是同步的话  这个回调是空的
      this.onFulfilledCallbacks.forEach(fn => fn())
    }

    const reject = reason => {
      if (this.status !== 'PENDING') return
      this.status = 'REJECTED'
      this.reason = reason
      this.onRejectedCallbacks.forEach(fn => fn())
    }

    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }

  then(onFulfilled, onRejected) {
    let newPromise = new myPromise((resolve, reject) => {
      let x = null
      switch (this.status) {
        case 'PENDING':
          // 因为异步 所以一直处于padding转态
          this.onFulfilledCallbacks.push(() => {
            x = onFulfilled(this.value)
            this.resolvePromise(newPromise, x, resolve, reject)

          })
          this.onRejectedCallbacks.push(() => {
            x = onRejected(this.reason)
            this.resolvePromise(newPromise, x, resolve, reject)

          })
          break;

        /**
         * 如果 resolve 是同步的话 就会执行下面的
         * 当处于异步的时候then已经调用了 即使
         * status的状态改变了 也不会执行
         */
        case 'FULFILLED':
          x = onFulfilled(this.value)
          this.resolvePromise(newPromise, x, resolve, reject)

          break;

        case 'REJECTED':
          x = onRejected(this.reason)
          this.resolvePromise(newPromise, x, resolve, reject)

          break;
      }
    })

    return newPromise
  }

  // 如果返回promise做相应处理 否则直接return 值
  resolvePromise(promise, x, resolve, reject) {
    if (promise === x) return reject(new TypeError('promise是同一个'))
    // 判断 x 是不是promise
    if (typeof x === 'object' && x != null || typeof x === 'function') {
      try {
        if (typeof x.then === 'function') {
          x.then(res => {
            this.resolvePromise(promise, res, resolve, reject)
          }, err => {
            reject(err)
          })
          return
        }
        resolve(x)
      } catch (err) {
        reject(err)
      }
    } else {
      // 如果不是直接调用resolve
      resolve(x)
    }
  }


  catch(onReJected) {
    return this.then(undefined, onReJected)
  }

  all(lists) {
    let resArr = [] //存储处理结果的数组
    let index = 0
    return new myPromise((resolve, reject) => {
      for (let i = 0; i < lists.length; i++) {
        lists[i].then(res => {
          resArr[i] = res
          index++
          if (index === lists.length) {
            resolve(resArr)
          }
        }).catch(err => {
          reject(err)
          return
        })
      }

    })
  }

}

new myPromise((resolve, reject) => {
  console.log(333)
  // resolve(1)
  setTimeout(() => resolve(1), 1000)
  console.log(222)
}).then(res => {
  return new myPromise((resolve, reject) => {
    console.log(2, res)
    resolve({
      name: "第2个传递的值"
    })
  })
}).then(res => {
  return new myPromise((resolve, reject) => {
    console.log(3, res)
    resolve(new myPromise((resolve, reject) => {
      console.log(3, res)
      resolve({
        name: "第3个传递的值"
      })
    }))
  })
}).then(res => {
  console.log(res, '555')
}).catch(err => {
  console.log(err, 'err')
})