「✍ Promise」

129 阅读2分钟

要写一个Promise,首先从使用他开始

乞丐版

let p = new Promise((resolve,reject)=>{
    // resolve('ok')
    setTimeout(()=>resolve('ok'), 100)
})

p.then(res=>{
  console.log(res) // ok
},(err)=>{
  console.log(err)
})

我们的关注点在于,p.thenresolve的执行顺序是不定的 (通常我们会做一篮子异步操作后再resolve出去)

那么不管它们的执行顺序是怎样的,我们需要保证最终then中的回调正常触发。

先来完成乞丐版的编写

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class _P {
  constructor(fn) {
    this.status = PENDING
    this.value = null
    this.err = null
    this.fulfilledArr = []
    this.rejectArr = []

    this.resolve = (value) => {
      // pending状态 ,扭转为fulfilled
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value // 保存参数,用于then的

        // 执行fulfilled中的所有回调
        this.fulfilledArr.forEach(cb => {
          cb(value)
        })
      }
    }

    this.reject = (value) => {
      // pending状态 ,扭转为reject
      if (this.status === PENDING) {
        this.status = REJECTED
        this.value = value // 保存参数,用于then的

        // 执行fulfilled中的所有回调
        this.rejectArr.forEach(cb => {
          cb(value)
        })
      }
    }

    try {
      fn(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
}

_P.prototype.then = function (onFulfilled, onReject) {
  if (this.status === FULFILLED) {
    onFulfilled(this.value)
  }

  if (this.status === REJECTED) {
    onReject(this.err)
  }

  if (this.status === PENDING) {
    this.fulfilledArr.push(() => {
      onFulfilled(this.value)
    })
    this.rejectArr.push(() => {
      onReject(this.err)
    })
  }
}

要点:

构造Promise时,,会执行传入的回调函数,假设:

1.构造函数中我们没有做异步,且很快的resolvereject(假设此时then还没运行),那么在resolve/reject中执行回调列表时,会发现没有函数可能执行,但status已经扭转,当后续then执行的时候,根据状态执行对应的回调,

2.构造函数中做了异步,导致then回调是先执行的,这时就会命中 if(this.status === PENDING) ,将回调函数塞到对应的任务队列中,当构造中的异步函数执行完,开始执行resolve / reject时,回调列表 列表就可以被执行了

链式调用

链式调用即在then方法中需要返回一个promise, 这里有分为两种情况

p.then(res => {
  return 'hello'
  return Promise.resolve('hello')
}).then(res => {
  console.log(res) // hello
})

我们在then中可以返回一个Promise或常量,而我们希望下一个then可以正常接收到"hello"

返回常量

用递归即可,const res = onFulfilled(this.value), 把结果resolve出去即可

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class _P {
  constructor(fn) {
    this.status = PENDING
    this.value = null
    this.err = null
    this.fulfilledArr = []
    this.rejectArr = []

    this.resolve = (value) => {
      // pending状态 ,扭转为fulfilled
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value // 保存参数,用于then的

        // 执行fulfilled中的所有回调
        this.fulfilledArr.forEach(cb => {
          cb(value)
        })
      }
    }

    this.reject = (value) => {
      // pending状态 ,扭转为reject
      if (this.status === PENDING) {
        this.status = REJECTED
        this.value = value // 保存参数,用于then的

        // 执行fulfilled中的所有回调
        this.rejectArr.forEach(cb => {
          cb(value)
        })
      }
    }

    try {
      fn(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
}

_P.prototype.then = function (onFulfilled, onReject) {
  let next = new _P((resolve, reject) => {
    if (this.status === FULFILLED) {
      const res = onFulfilled(this.value)
      resolve(res)
    }

    if (this.status === REJECTED) {
      const res = onReject(this.value)
      resolve(res)
    }

    if (this.status === PENDING) {
      // 如果状态还是PENDING,把事件装进回调数组
      this.fulfilledArr.push(() => {
        const res = onFulfilled(this.value)
        resolve(res)
      })
      this.rejectArr.push(() => {
        const res = onReject(this.err)
        reject(res)
      })
    }
  })
  return next
}

返回Promise

..to be continue