从零手撕Promise,掌握Promise的实现原理(11)之测试完全体Promise是否符合PromiseA+

387 阅读4分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。

传送门

从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么 从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现 从零手撕Promise,掌握Promise的实现原理(5)之then方法链式调用的进阶实现  从零手撕Promise,掌握Promise的实现原理(6)之then方法的回调为什么是异步微任务 从零手撕Promise,掌握Promise的实现原理(7)then方法链式调用之核心方法resolvePromise 从零手撕Promise,掌握Promise的实现原理(8)then方法链式调用之核心方法resolvePromise再探究 从零手撕Promise,掌握Promise的实现原理(9)then方法链式调用之核心方法resolvePromise完全体 从零手撕Promise,掌握Promise的实现原理(10)then方法完全体

回顾

经过10篇文章的介绍我们的Promsie已经完成了,接下来我们准备通过一个第三方的npm包来测试一下我们的Promise是否符合Promise A+规范。

现在完全体的Promise长这样

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const resolvePromise = (promise, x, resolve, reject) => {
  //*******************************************************判断x与promsie是否是同一个promise,防止进入死循环*********************//////*********
  if(x === promise) throw new TypeError('Chaining cycle detected for promise #<Promise>')
  // 1.首先判断`x`是基础类型数据,还是引用类型,基础类型的数据直接`resolve`,即可。  
  if(x !== null && /^(object|function)$/.test(typeof x)){
    let then 
    // 2. 如果是引用类型的数据,尝试获取`x`上的`then`属性(`x.then`),如果在获取属性的时候报异常则`reject`
    try{
      then = x.then
    }catch(e){
      reject(e)
    }
    //3. 判断`then`是否是函数,如果是一个函数则我们认定它为`Promise`,如果不是则`resolve`
    if(typeof then === 'function'){
      let called = false //**************************************这里加了变量*************************//////
      try{
        then.call(x, (y) => {
          if(called) return //**************************************这里加了变量*************************//////
          called = true
          resolvePromise(promise, y, resolve, reject)
        },(r) => {
          if(called) return//**************************************这里加了变量*************************//////
          reject(r)
        })
      }catch(e){
        if(called) return//**************************************这里加了变量*************************//////
        reject(e)
      }
    }else{
      resolve(x)
    }
  }else{
    //基础类型数据直接resolve
    resolve(x)
  }
}
class Promise{
  constructor(executor){

    this.state = PENDING
    this.value = undefined
    this.reason = undefined
    //存放onFulfilled
    this.onResolvedCallbacks = []
    //存放onRejected
    this.onRejectedCallbacks = []
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value
        this.state = FULFILLED
        //promise实例状态改变后调用暂存的onFulfilled
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason
        this.state = REJECTED
        //promise实例状态改变后调用的onRejected
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      //executor函数执行过程中出错,将会导致Promise失败
      executor(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }
  then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
    let promise = new Promise((resolve, reject) => {
        
        switch(this.state){
          case FULFILLED:
              setTimeout(() => {
                try{
                  let x = onFulfilled(this.value)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })   
              break
          case REJECTED:
              setTimeout(() => {
                try{
                  let x = onRejected(this.reason)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })   
              break
          default:
            this.onResolvedCallbacks.push(() => {
              setTimeout(() => {
                try{
                  let x = onFulfilled(this.value)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })
            })
            this.onRejectedCallbacks.push(() => {
              setTimeout(() => {
                try{
                  let x = onRejected(this.reason)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })
            })
        }
    })
    return promise
  }
}

测试流程

    1. npm init --yes 初始化package.json
    1. npm i promise-aplus-tests -D 本地安装测试Promise的第三方包
    1. index.js文件中,放入我们要测试的Promise,并加入以下代码.
    • 这段代码很简单,在Promise上扩展一个静态的方法,这个方法返回一个对象dfddfd上有三个属性,一个是Promsie实例,另外两个分别是其对应的resolvereject
    • 其实就是相当于调用这个方法,可以创建一个Promise实例,并把这个实例返回。
    Promise.deferred = function(){
    let dfd = {}
    dfd.promise = new Promise((resolve,reject)=>{
          dfd.resolve = resolve;
          dfd.reject = reject;
      })
      return dfd;
    }
    
    1. 最后导出我们的Promsie
    module.exports = Promise
    
    

index.js长这样

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const resolvePromise = (promise, x, resolve, reject) => {
  //*******************************************************判断x与promsie是否是同一个promise,防止进入死循环*********************//////*********
  if(x === promise) throw new TypeError('Chaining cycle detected for promise #<Promise>')
  // 1.首先判断`x`是基础类型数据,还是引用类型,基础类型的数据直接`resolve`,即可。  
  if(x !== null && /^(object|function)$/.test(typeof x)){
    let then 
    // 2. 如果是引用类型的数据,尝试获取`x`上的`then`属性(`x.then`),如果在获取属性的时候报异常则`reject`
    try{
      then = x.then
    }catch(e){
      reject(e)
    }
    //3. 判断`then`是否是函数,如果是一个函数则我们认定它为`Promise`,如果不是则`resolve`
    if(typeof then === 'function'){
      let called = false //**************************************这里加了变量*************************//////
      try{
        then.call(x, (y) => {
          if(called) return //**************************************这里加了变量*************************//////
          called = true
          resolvePromise(promise, y, resolve, reject)
        },(r) => {
          if(called) return//**************************************这里加了变量*************************//////
          reject(r)
        })
      }catch(e){
        if(called) return//**************************************这里加了变量*************************//////
        reject(e)
      }
    }else{
      resolve(x)
    }
  }else{
    //基础类型数据直接resolve
    resolve(x)
  }
}
class Promise{
  constructor(executor){

    this.state = PENDING
    this.value = undefined
    this.reason = undefined
    //存放onFulfilled
    this.onResolvedCallbacks = []
    //存放onRejected
    this.onRejectedCallbacks = []
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value
        this.state = FULFILLED
        //promise实例状态改变后调用暂存的onFulfilled
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason
        this.state = REJECTED
        //promise实例状态改变后调用的onRejected
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      //executor函数执行过程中出错,将会导致Promise失败
      executor(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }
  then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
    let promise = new Promise((resolve, reject) => {
        
        switch(this.state){
          case FULFILLED:
              setTimeout(() => {
                try{
                  let x = onFulfilled(this.value)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })   
              break
          case REJECTED:
              setTimeout(() => {
                try{
                  let x = onRejected(this.reason)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })   
              break
          default:
            this.onResolvedCallbacks.push(() => {
              setTimeout(() => {
                try{
                  let x = onFulfilled(this.value)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })
            })
            this.onRejectedCallbacks.push(() => {
              setTimeout(() => {
                try{
                  let x = onRejected(this.reason)
                  resolvePromise(promise, x, resolve, reject)
                } catch(e){
                  reject(e)
                }
              })
            })
        }
    })
    return promise
  }
}

Promise.deferred = function(){
  let dfd = {}
  dfd.promise = new Promise((resolve,reject)=>{
      dfd.resolve = resolve;
      dfd.reject = reject;
  })
  return dfd;
}




module.exports = Promise

添加测试的执行脚本

  • package.json中添加下面的脚本
"scripts": {
    "test": "promises-aplus-tests index.js"
},
  • 在终端输入npm run test

test-pa.gif

最终测试完美通过Promise A+规范,大家可以试试

下一篇文章继续,介绍Promise的其他方法

传送门

从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么 从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现 从零手撕Promise,掌握Promise的实现原理(5)之then方法链式调用的进阶实现  从零手撕Promise,掌握Promise的实现原理(6)之then方法的回调为什么是异步微任务 从零手撕Promise,掌握Promise的实现原理(7)then方法链式调用之核心方法resolvePromise 从零手撕Promise,掌握Promise的实现原理(8)then方法链式调用之核心方法resolvePromise再探究 从零手撕Promise,掌握Promise的实现原理(9)then方法链式调用之核心方法resolvePromise完全体 从零手撕Promise,掌握Promise的实现原理(10)then方法完全体