xiaokeqi / i-learned

1 stars 0 forks source link

Promise实现 #26

Open xiaokeqi opened 5 years ago

xiaokeqi commented 5 years ago

状态实现 pending->fullfilled or rejected

new Promise(function(resolve,reject){
    setTimeout(function(){
         resolve(10)
    },1000)
})

从上面例子上看,实现一个Promise,可定义一个类

class Promise{
     constructor(handle){
         this._status = 'PENDING';
         this._value = undefined
         handle(this._resolve, this._reject);
     }
     _resolve(val) {
         if (this._status !== PENDING) return
         this._status = FULFILLED
         this._value = val
    }
   _reject(err) {
          if (this._status !== PENDING) return
          this._status = REJECTED
          this._value = err
    }
}
xiaokeqi commented 5 years ago

Promise.then 实现

then 方法接受两个参数: promise.then(onFulfilled, onRejected)

  1. 参数都是可选,如果 onFulfilled 或 onRejected 不是函数,其必须被忽略
  2. 当 promise 状态变为成功或失败时时必须被调用,其第一个参数为 promise 成功状态传入的值( resolve 执行时传入的值)在 promise 状态改变前其不可被调用
  3. then 方法必须返回一个新的 promise 对象,支持链式调用 例子
    let promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve()
    }, 1000)
    })
    promise2 = promise1.then(res => {
    // 返回一个普通值
    return '这里返回一个普通值'
    })
    promise2.then(res => {
    console.log(res) //1秒后打印出:这里返回一个普通值
    })
let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, 1000)
})
promise2 = promise1.then(res => {
  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    setTimeout(() => {
     resolve('这里返回一个Promise')
    }, 2000)
  })
})
promise2.then(res => {
  console.log(res) //3秒后打印出:这里返回一个Promise
})

如果 onFulfilled 或者onRejected 抛出一个异常 e ,则 promise2 必须变为失败(Rejected),并返回失败的值 e,例如

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
promise2 = promise1.then(res => {
  throw new Error('这里抛出一个异常e')
})
promise2.then(res => {
  console.log(res)
}, err => {
  console.log(err) //1秒后打印出:这里抛出一个异常e
})

3、如果onFulfilled 不是函数且 promise1 状态为成功(Fulfilled), promise2 必须变为成功(Fulfilled)并返回 promise1 成功的值,OnReject同样是这样例如:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
promise2 = promise1.then('这里的onFulfilled本来是一个函数,但现在不是')
promise2.then(res => {
  console.log(res) // 1秒后打印出:success
}, err => {
  console.log(err)
})
xiaokeqi commented 5 years ago

修改 constructor : 增加执行队列

由于 then 方法支持多次调用,我们可以维护两个数组,将每次 then 方法注册时的回调函数添加到数组中,等待执行

class Promise{
     constructor(handle){
         this._status = 'PENDING';
         this._value = undefined
         // 添加成功回调函数队列
         this._fulfilledQueues = []
          // 添加失败回调函数队列
         this._rejectedQueues = []
        // 执行handle
        try {
             handle(this._resolve.bind(this), this._reject.bind(this)) 
        } catch (err) {
             this._reject(err)
        }
     }
     _resolve(val) {
         if (this._status !== PENDING) return
         this._status = FULFILLED
         this._value = val
    }
   _reject(err) {
          if (this._status !== PENDING) return
          this._status = REJECTED
          this._value = err
    }
}
xiaokeqi commented 5 years ago

首先,then 返回一个新的 Promise 对象,并且需要将回调函数加入到执行队列中

then (onFulfilled, onRejected) {
  const { _value, _status } = this
  switch (_status) {
    // 当状态为pending时,将then方法回调函数加入执行队列等待执行
    case PENDING:
      this._fulfilledQueues.push(onFulfilled)
      this._rejectedQueues.push(onRejected)
      break
    // 当状态已经改变时,立即执行对应的回调函数
    case FULFILLED:
      onFulfilled(_value)
      break
    case REJECTED:
      onRejected(_value)
      break
  }
  // 返回一个新的Promise对象
  return new MyPromise((onFulfilledNext, onRejectedNext) => {
  })
}

因为调用then方法时,还不确定staus状态值,异步返回时间不定,故需要根据status值做判断 若status已经是fullfilled,直接执行resolve函数,若rejected,直接执行rejected函数 若为pending,则需要加入到执行队列里面去,因为我们不知道promise调用了多少个then方法

xiaokeqi commented 5 years ago

https://juejin.im/post/5b83cb5ae51d4538cc3ec354

参考网址

xiaokeqi commented 5 years ago

Promise.resolve和Promise.reject

Promise.resolve方法的实现其实就是通过

function resolve(value) {
      if (value instanceof MyPromise) return value
    return new Promise(function(resolve){resolve(value)})
}

实现 Promise.reject 同理

xiaokeqi commented 5 years ago

Promise.all

Promise.all 是要所有promise请求均resolve才会返回结果,并且按照顺序放回,不能打乱顺序

function all(list){
    return new MyPromise((resolve, reject) => {
    /**
     * 返回值的集合
     */
            let values = []
            let count = 0
             for (let [i, p] of list.entries()) {
                   // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
                this.resolve(p).then(res => {
                      values[i] = res
                      count++
                     // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
                     if (count === list.length) resolve(values)
                }, err => {
                    // 有一个被rejected时返回的MyPromise状态就变成rejected
                  reject(err)
           })
       }
  })
}