JavaScript手写系列(十八)(手写Promise、Promise.all、Promise.race、Promise.retry)

106 阅读1分钟

Promise 是异步编程的一种解决方案: 从语法上讲, promise是一个对象,从它可以获取异步操作的消息; 从本意上讲, 它是承诺, 承诺它过一段时间会给你一个结果 promise有三种状态: pending(等待态), fulfiled(成功态), rejected(失败态); 状态一旦改变, 就不会再变; 创造promise实例后, 它会立即执行

Promise的实现

class MyPromise {
  constructor(fn) {
    this.resolvedCallbacks = []
    this.rejectedCallbacks = []
    
    this.state = 'PENDING'
    this.value = ''
    
    fn(this.resolve.bind(this), this.reject.bind(this))
    
  }
  
  resolve(value) {
    if (this.state === 'PENDING') {
      this.state = 'RESOLVED'
      this.value = value
      
      this.resolvedCallbacks.map(cb => cb(value))   
    }
  }
  
  reject(value) {
    if (this.state === 'PENDING') {
      this.state = 'REJECTED'
      this.value = value
      
      this.rejectedCallbacks.map(cb => cb(value))
    }
  }
  
  then(onFulfilled, onRejected) {
    if (this.state === 'PENDING') {
      this.resolvedCallbacks.push(onFulfilled)
      this.rejectedCallbacks.push(onRejected)
    }
    
    if (this.state === 'RESOLVED') {
      onFulfilled(this.value)
    }   
    
    if (this.state === 'REJECTED') {
      onRejected(this.value)
    }
  }
}

Promise.all

Promise.all = function(arr) {
    return new Promise((resolve, reject) => {
        if(!Array.isArray(arr)) {
            throw new TypeError(`argument must be a array`)
        }
        let length = arr.length
        let resolveNum = 0
        let resolveResult = []
        for (let i = 0; i < length; i++) {
            arr[i].then(data => {
                resolveNum++
                resolveResult.push(data)
                if (resolveNum === length) {
                    return resolve(resolveResult)
                }
            }).catch(data => {
                return reject(data)
            })
        }
    })
}

Promise.race

  • Promse.race就是赛跑的意思, 意思就是说, Promise.race([p1, p2, p3])里面哪个结果获得的快, 就返回那个结果, 不管结果本身是成功状态还是失败状态
  • Promise.race方法里的参数不一定都是promise, 当不是promise的时候会把它转换为promise
Promise.race = function(arr) {
  if (!Array.isArray(arr)) {
    throw new typeError('argument must be array')
  }
  return new Promise((resolve, reject) => {
    for(let i = 0; i < arr.length; i++) {
      Promise.resolve(arr[i]).then(val => resolve(val), err => reject(err))
    }
  })
}

Promise.retry

promise.retry的作用是执行一个函数, 如果不成功最多可以尝试times次.传参需要三个变量, 所要执行的函数, 尝试的次数以及间隔尝试的时间

Promise.retry = function(fn, times, delay) {
    return new Promise((resolve, reject) => {
        let error
        let attemp = function() {
            if (times == 0) {
                reject(error)
            } else {
                fn().then(resolve)
                    .catch(e => {
                        times--
                        error = e
                        setTimeout(function(){attempt()}, delay)
                    })
            }
        }
        attemp()
    })
}