按部就班实现Promise

实现promise要在熟练使用的基础上完成,首先要明确几点数组

  1. promise是一个类
  2. promise有三种状态:成功(fulfilled)、失败(rejected)、等待(pending)
    1. pending -> fulfilled / rejected
    2. 状态一旦肯定就不能够再改变
  3. resolve和reject函数是用来改变状态的
    1. resolve: fulfilled
    2. reject: rejected
  4. 调用then方式传入两个参数,第一个参数为状态fulfilled时的回调函数,第二个参数为状态为rejected时的回调函数

初版 - 基础核心原理的实现

const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(exector) {
    exector(this.reslove, this.reject)
  }
  
  status = PENDING // promise状态
  value = undefined // 成功时的值 then方法须要返回
  error = undefined // 失败时的值 then方法须要返回
  
  // 成功时的函数
  reslove = value => {
    // 修改promise状态
    this.status = FULFILLED
    this.value = value
  }
  // 失败时的函数
  reject = error => {
    // 修改promise状态
    this.status = REJECTED
    this.error = error
  }
  
  then(successCallback, failCallback) {
    switch (this.status) {
            case FULFILLED:
                successCallback(this.value)
                break
            case REJECTED:
                failCallback(this.error)
                break
                
        }
  }
}
// test
const promise = new MyPromise((reslove, reject) => {
    reslove('reslove')
})
  
promise.then(value => {
    console.log(value) // reslove
}, error => {
    console.log(error)
})
复制代码

经过上面的代码,咱们成功实现了对promise基础原理。调用promise.then方法能够成功打印出‘reslove’。可是,在then方法的实现中咱们并无对PENDING状态作处理。也就是说,假如咱们进行异步操做,当前的promise是没法处理的。好比:promise

const promise = new MyPromise((reslove, reject) => {
  setTimeout(()=> {
    reslove('reslove')
  },2000)
})
复制代码

第二版 - 处理异步状况

那么异步状况如何处理呢?以上面setTimeout为例,reslove是在2秒后执行,在调用then方法2秒内当前promise的状态仍然为PENDING。 两步解决:markdown

  1. PENDING状态时,对成功or失败回调做暂存
  2. 在reslove/reject 函数中判断是否有回调函数,有则执行
const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(exector) {
    exector(this.reslove, this.reject)
  }
  
  status = PENDING // promise状态
  value = undefined // 成功时的值 then方法须要返回
  error = undefined // 失败时的值 then方法须要返回
    successCallback = undefined // 成功回调
    failCallback = undefined // 失败回调
  // 成功时的函数
  reslove = value => {
    // 修改promise状态
    this.status = FULFILLED
    this.value = value
    this.successCallback && this.successCallback(this.value)
  }
  // 失败时的函数
  reject = error => {
    // 修改promise状态
    this.status = REJECTED
    this.error = error
    this.failCallback && this.failCallback(this.error)
  }
  then(successCallback, failCallback) {
    switch (this.status) {
            case FULFILLED:
                successCallback(this.value)
                break
            case REJECTED:
                failCallBack(this.error)
                break
      // 异步状况处理
      case PENDING:
        this.successCallback = successCallback
        this.failCallback = failCallback
                break
        }
  }
}
// test
const promise = new MyPromise((reslove, reject) => {
    setTimeout(()=> {
        reslove('reslove')
    }, 2000)    
})
  
promise.then(value => {
    console.log(value) // 2秒后: reslove
}, error => {
    console.log(error)
})
复制代码

实现第二版后,问题又来了。咱们平时使用promise时同一个promise下的then方法是能够屡次调用的。咱们将测试代码改成异步

// test
const promise = new MyPromise((reslove, reject) => {
  setTimeout(()=> {
    reslove('reslove')
  }, 2000)  
})
promise.then(value => {
    console.log('第一次调用then: ', value)
})
promise.then(value => {
    console.log('第二次调用then: ', value)
})
// 第二次调用then reslove
复制代码

发现代码只执行了最后一次then方法,打印“第二次调用then: reslove”。这显然是与咱们的预期不相符的函数

第三版 - 屡次调用

要实现屡次调用,咱们须要作的是: 以数组形式暂存多个callback,而且在reslove/reject的时候依次调用测试

const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
  constructor(exector) {
    exector(this.reslove, this.reject)
  }
  status = PENDING // promise状态
  value = undefined // 成功时的值 then方法须要返回
  error = undefined // 失败时的值 then方法须要返回
  // 数组暂存
  successCallback = [] // 成功回调
  failCallback = [] // 失败回调
  // 成功时的函数
  reslove = value => {
    // 修改promise状态
    this.status = FULFILLED
    this.value = value
    // 依次调用
    while(this.successCallback.length) this.successCallback.shift()(this.value)
  }
  // 失败时的函数
  reject = error => {
    // 修改promise状态
    this.status = REJECTED
    this.error = error
    // 依次调用
    while(this.failCallback.length) this.failCallback.shift()(this.error)
  }
  then(successCallback, failCallback) {
    switch (this.status) {
      case FULFILLED:
        successCallback(this.value)
        break
      case REJECTED:
        failCallBack(this.error)
        break
        // 异步状况处理
      case PENDING:
        this.successCallback.push(successCallback)
        this.failCallback.push(failCallback)
        break
    }
  }
}
// test
const promise = new MyPromise((reslove, reject) => {
  setTimeout(()=> {
    reslove('reslove')
  }, 2000)  
})
promise.then(value => {
  console.log('第一次调用then: ', value)
})
promise.then(value => {
  console.log('第二次调用then: ', value)
})
promise.then(value => {
  console.log('第三次调用then: ', value)
})
// 第一次调用then: reslove
// 第二次调用then: reslove
// 第三次调用then: reslove 
复制代码

除了屡次调用外,promise还支持链式调用。而且后面then方法的回调函数拿到的值是上一个then方法的回调函数的返回值。优化

第四版 - 链式调用

这里值得注意的是,咱们须要判断上一个then的返回值是什么类型。若是是普通的值,能够直接调用reslove方法。若是是promise对象,则须要根据promise对象返回的结果来决定调用reslove或者reject。ui

const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
  constructor(exector) {
    exector(this.reslove, this.reject)
  }
  status = PENDING // promise状态
  value = undefined // 成功时的值 then方法须要返回
  error = undefined // 失败时的值 then方法须要返回
  successCallback = [] // 成功回调
  failCallback = [] // 失败回调
  // 成功时的函数
  reslove = value => {
    // 修改promise状态
    this.status = FULFILLED
    this.value = value
    while(this.successCallback.length) this.successCallback.shift()(this.value)
  }
  // 失败时的函数
  reject = error => {
    // 修改promise状态
    this.status = REJECTED
    this.error = error
    while(this.failCallback.length) this.failCallback.shift()(this.error)
  }
  then(successCallback, failCallback) {
    return new Promise((reslove, reject) => {
      switch (this.status) {
        case FULFILLED:
          reslovePromise(successCallback(this.value), reslove, reject)  
          break
        case REJECTED:
          failCallBack(this.error)
          break
          // 异步状况处理
        case PENDING:
          this.successCallback.push(successCallback)
          this.failCallback.push(failCallback)
          break
      }
    })  
  }
}
// 通用方法 - 解析promise对象 (PENDING、 FULFILLED、REJECTED都会用到)
function reslovePromise(x, reslove, reject) {
  if (x instanceof MyPromise) {
    x.then(reslove, reject)
  } else {
    reslove(x)
  }
}
// test
const promise = new MyPromise((reslove, reject) => {
  reslove('reslove')    
})
promise.then(value => {
  console.log('第一次调用then: ', value)
  return 'reslove2'
}).then(value => {
  console.log('第二次调用then: ', value)
  return new MyPromise((reslove, reject) => {
    reslove('reslove3')
  })
}).then(value => {
  console.log('第三次调用then: ', value)
})
// 第一次调用then: reslove
// 第二次调用then: reslove2
// 第三次调用then: reslove3
复制代码

到第四版,咱们的MyPromise实现了promise的基本功能。但从代码能够看出,咱们并未对MyPromise作任何错误处理,这并非一段健壮的代码该有的样子。那么接下来,咱们就对MyPromise作一些代码优化及错误处理。this

第五版 - 代码优化及错误处理

错误处理想到了两方面。一是在reslove方法执行报错时,将状态改成REJECTED,执行reject方法。二是识别promise返回自对象。spa

const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(exector) {
        try {
            exector(this.reslove, this.reject)
        } catch(e) {
            this.reject(e)
        }
    }

    status = PENDING // promise状态
    value = undefined // 成功时的值 then方法须要返回
    error = undefined // 失败时的值 then方法须要返回
    successCallback = [] // 成功回调
    failCallback = [] // 失败回调
    // 成功时的函数
    reslove = value => {
        // 修改promise状态
        this.status = FULFILLED
        this.value = value
        while(this.successCallback.length) this.successCallback.shift()()
    }
    // 失败时的函数
    reject = error => {
        // 修改promise状态
        this.status = REJECTED
        this.error = error
        while(this.failCallback.length) this.failCallback.shift()()
    }
    then(successCallback, failCallback) {
        // 将then方法的参数变为可选参数
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : error => {throw error}
        let newPromise = new MyPromise((reslove, reject) => {
            switch (this.status) {
                case FULFILLED:
                    setTimeout(()=> {
                        try {
                            reslovePromise(newPromise, successCallback(this.value), reslove, reject)
                        } catch(e) {
                            reject(e)
                        }       
                    }, 0)               
                    break
                case REJECTED:
                setTimeout(()=> {
                        try {
                            reslovePromise(newPromise, failCallback(this.error), reslove, reject)
                        } catch(e) {
                            reject(e)
                        }       
                    }, 0)
                    break
                // 异步状况处理
                case PENDING:
                    this.successCallback.push(()=> {
                        setTimeout(()=> {
                            try {
                                reslovePromise(newPromise, successCallback(this.value), reslove, reject)
                            } catch(e) {
                                reject(e)
                            }       
                        }, 0)
                    })
                    this.failCallback.push(()=> {
                        setTimeout(()=> {
                            try {
                                reslovePromise(newPromise, failCallback(this.error), reslove, reject)
                            } catch(e) {
                                reject(e)
                            }       
                        }, 0)
                    })
                    break
            }
        })
        return newPromise   
    }
}
// 通用方法 - 解析promose对象 (PENDING、 FULFILLED、REJECTED都会用到)
function reslovePromise(newPromise ,x, reslove, reject) {
    if (newPromise === x) {
        return reject(new TypeError('循环调用'))
    }
    if (x instanceof MyPromise) {
        x.then(reslove, reject)
    } else {
        reslove(x)
    }
}
// test
const promise = new MyPromise((reslove, reject) => {
    setTimeout(()=> {
        reslove('reslove')
    }, 2000)

    // reject('reject')
})
promise.then(value => {
    console.log('第一次调用then reslove: ', value)
    throw new Error('then error')
}, error => {
    console.log('第一次调用then reject: ', error)
}).then(value => {
    console.log('第二次调用then reslove: ', value)
}, error => {
    console.log('第二次调用then reject: ', error)
})
// 第一次调用then reslove: reslove
// 第二次调用then reject: Error: then error
复制代码
相关文章
相关标签/搜索