手写A+ Promise

题目:手写A+ Promise

一、前言

在手写promise之前我们先来了解一下什么是promiseA+ 规范,附上链接:Promise A+规范,我简单根据这个A+规范总结一下,包括本次手写Promise也是简单实现一下部分的需求;

(1):如果用面向对象的角度考虑,Promise是一个类,所有实例拥有三个属性,而且应该属于是私有属性
(2):三个属性分别是state(保存着当前promise的状态),状态的取值必须是pending (进行中), fullfilled (成功), rejected(失败)三种。
(3):每创建一个promise都必须传递一个回调函数,回调函数执行时(同步执行的),接受两个参数resolve,reject,并且这两个回调是异步执行的。
(4):实例都可以调用.then方法,这个方法接受两个参数成功的回调失败的回调,如果当前实例成功则会执行成功的回调,并把成功的参数传递给这个回调,失败则是同理,这个.then的回调函数也是异步执行。
(5):返回的promise的状态取决于回调函数中返回的值,如果返回的不是一个promise的实例,那么返回的promise属于成功的状态,值为回调的返回值,如果是一个promise,那么返回的promise的状态取决于这个Promise的状态。并保持一致。
(6):如果抛出错误那么会进入异常穿透穿透环节,只要在任意回调中抛出了错误,那么promise会拦截这个错误,无论调用多少次.then最终返回的依然是个失败的promise,并且值为抛出的异常

小结:这个是我总结的promiseA+规范中的部分规范,当然并不完全,但姑且谅解我们先从简单的开始好吗?


接下来我们来一起实现一下吧

  • 先创建一个类也就是专门的promise类,我们使用ES6的新语法 class , 当然现在也已经不能算新语法了哈。
const Pending = 'pending'
const Fullfilled = 'fullfilled'
const Rejected = 'rejected'

class Promise {
  constructor(executor) {
    this.result = ''
    this.state = Pending
           //  ?          ?
    executor(resolve, reject)
  }
}

已经创建好了一个类,并且拥有自己的状态和结果值,而且当执行器函数传过来的时候要求要同步调用,因此我们直接调用它,我们需要在构造函数中定义一下那两个回调函数,这里需要注意,这个回调函数必须是异步的,而且我们需要准备一个容器数组来存储.then传入的回调函数。(这里的原因我们稍后会讲到!)

const Pending = 'pending'
const Fullfilled = 'fullfilled'
const Rejected = 'rejected'

class Promise {
  constructor(executor) {
    this.result = ''
    this.state = Pending
    // 容器数组
    this.callbacks = []
    const _this = this
    const resolve = (result) => {
      this.result = result
      this.state = Fullfilled
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onResolved && cb.onResolved(result)
        })
      })

    }

    const reject = result => {
      this.result = result
      this.state = Rejected
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onRejected && cb.onRejected(result)
        })
      })
    }

    executor(resolve, reject)
  }
}

回调函数属于异步调用的因此我们使用定时器来模拟,其次如果回调容器数组callbacks有回调函数的话,还将其一一进行执行,在定义这两个回调是,我们首要的任务应该是改变当前promise的状态,如果成功的话将这个promise的状态改为fullfilled,如果失败的话将这个promise的状态改为rejected

接下来要做的事情就是实现then方法了,这个方法算是promise的核心了,只要实现了promise的.then方法,那么其他的方法比如.catch ,.all ,.race等等就容易多了,接下来我们就一起来实现一下。

class Promise {
  constructor(executor) {
    this.result = ''
    this.state = Pending
    // 容器数组
    this.callbacks = []
    const _this = this
    const resolve = (result) => {
      this.result = result
      this.state = Fullfilled
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onResolved && cb.onResolved(result)
        })
      })

    }

    const reject = result => {
      this.result = result
      this.state = Rejected
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onRejected && cb.onRejected(result)
        })
      })
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then (onResolved, onRejected) {
    const _this = this
    return new Promise((resolve, reject) => {
      const callback = cb => {
        setTimeout(() => {
          try {
            let result = cb(_this.result)
            if (!(result instanceof Promise)) {
              resolve(result)
            } else {
              result.then(res => {
                resolve(res)
              }, reason => {
                reject(reason)
              })
            }
          } catch (error) {
            reject(error)
          }
        })
      }
      if (_this.state === Pending) {
        // 还在pending当中
        _this.callbacks.push({
          onResolved,
          onRejected
        })
      } else if (_this.state === Fullfilled) {
        callback(onResolved)
      } else if (_this.state === Rejected) {
        callback(onRejected)
      }
    })
  }
}

实现promise的then方法主要有几个核心,第一就是要返回一个新的Promise,所以我们二话不说先 return new Promise(( resolve,reject)=>{}) 先返回一个新的Promise,至于这个promise到底是什么样的状态呢,我们要进行判断

  • 首先我们先判断一下当前promise是什么样的状态,有三种情况,首先如果是进行中的话(也就是在我们调用.then的时候上一个promise的状态还没有改变,也就是先指定回调后进行执行的情况),这个时候我们也不能立即对promise指定结果,我们可以将回调添加到callbacks当中,当上一个promise有结果的时候再进行一个调用就可以了(但是这个地方其实还有个坑稍后会讲到)。
  • 其次,当前Promise如果要是已经是fullfilled状态的话,我们就要执行成功的回调,因为返回的Promise的状态由当前的回调返回值决定,因此我们可以获取返回的结果,再判断一下是不是promise的实例,如果是的话就再讲这个promise进行.then处理获取状态,如果不是的话就直接当当前的promise置为一个成功的状态。
  • 在这里需要注意的是,第一步我们在当前promise为pending状态时,直接添加回调即可,这种做法肯定是不对的,因此就算回调后面执行了这个回调,当时并没有更改当前返回的这个promise的状态呀,所以我们需要扩展回调的功能,不仅需要执行回调而且还需要改变返回的promise的状态,我们急需将代码完成以下。
const Pending = 'pending'
const Fullfilled = 'fullfilled'
const Rejected = 'rejected'

class Promise {
  constructor(executor) {
    this.result = ''
    this.state = Pending
    // 容器数组
    this.callbacks = []
    const _this = this
    const resolve = (result) => {
      this.result = result
      this.state = Fullfilled
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onResolved && cb.onResolved(result)
        })
      })

    }

    const reject = result => {
      this.result = result
      this.state = Rejected
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onRejected && cb.onRejected(result)
        })
      })
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then (onResolved, onRejected) {
    const _this = this
    return new Promise((resolve, reject) => {
      const callback = cb => {
        setTimeout(() => {
          try {
            let result = cb(_this.result)
            if (!(result instanceof Promise)) {
              resolve(result)
            } else {
              result.then(res => {
                resolve(res)
              }, reason => {
                reject(reason)
              })
            }
          } catch (error) {
            reject(error)
          }
        })
      }
      if (_this.state === Pending) {
        // 还在pending当中
        _this.callbacks.push({
          onResolved: () => {
            callback(onResolved)
          },
          onRejected: () => {
            callback(onRjected)
          }
        })
      } else if (_this.state === Fullfilled) {
        callback(onResolved)
      } else if (_this.state === Rejected) {
        callback(onRejected)
      }
    })
  }
}

好了这就是目前的较为完整的版本了,大家可以自行试一下,当然catch方法,和race方法也可以自行实现一下,我在这里就直接把代码奉上啦!

const Pending = 'pending'
const Fullfilled = 'fullfilled'
const Rejected = 'rejected'

class Promise {
  constructor(executor) {
    this.result = ''
    this.state = Pending
    // 容器数组
    this.callbacks = []
    const _this = this
    const resolve = (result) => {
      this.result = result
      this.state = Fullfilled
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onResolved && cb.onResolved(result)
        })
      })

    }

    const reject = result => {
      this.result = result
      this.state = Rejected
      setTimeout(() => {
        _this.callbacks.forEach(cb => {
          cb.onRejected && cb.onRejected(result)
        })
      })
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then (onResolved, onRejected) {
    const _this = this
    return new Promise((resolve, reject) => {
      const callback = cb => {
        setTimeout(() => {
          try {
            let result = cb && cb(_this.result)
            if (!(result instanceof Promise)) {
              resolve(result)
            } else {
              result.then(res => {
                resolve(res)
              }, reason => {
                reject(reason)
              })
            }
          } catch (error) {
            reject(error)
          }
        })
      }
      if (_this.state === Pending) {
        // 还在pending当中
        _this.callbacks.push({
          onResolved: () => {
            callback(onResolved)
          },
          onRejected: () => {
            callback(onRjected)
          }
        })
      } else if (_this.state === Fullfilled) {
        callback(onResolved)
      } else if (_this.state === Rejected) {
        callback(onRejected)
      }
    })
  }

  catch (onRejected) {
    return this.then(null, onRejected)
  }

  static race (promises) {
    // 这是一个数组,数组中有多个promise
    if (!Array.isArray(promises)) {
      return console.warn('参数不是可迭代的对象')
    }
    return new Promise((resolve, reject) => {
      promises.forEach(promise => {
        if (promise instanceof Promise) {
          promise.then(res => {
            resolve(res)
          }, reason => {
            reject(reason)
          })
        } else {
          resolve(promise)
        }
      })
    })
  }

  static all (promises) {
    if (!Array.isArray(promises)) {
      return console.warn('参数不是可迭代的对象')
    }
    return new Promise((resolve, reject) => {
      let resArr = []
      let index = 0
      let length = promises.length
      promises.forEach(promise => {
        if (promise instanceof Promise) {
          promise.then(res => {
            resArr.push(res)
            index++
            if (index == length) {
              resolve(resArr)
            }
          }, reason => {
            reject(reason)
          })
        } else {
          resArr.push(promise)
          index++
          if (index == length) {
            resolve(resArr)
          }
        }
      })
    })
  }

  static resolve (value) {
    return new Promise((resolve, reject) => {
      resolve(value)
    })
  }
}

后记

本文还是有不严谨和疏忽的地方,希望有读者阅读并欢迎批评指正,我一定第一时间更改,成为一名优秀的前端工程师,我们一直在路上,加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值