跳至主要內容

promise 实现

wzCoding大约 4 分钟综合知识promise 实现

promise 实现

实现标准

promise 经常用来处理异步任务,它的实现标准在 Promises/A+ 规范中有明确描述:

“promise” is an object or function with a then method whose behavior conforms to this specification.

“thenable” is an object or function that defines a then method.

“value” is any legal JavaScript value (including undefined, a thenable, or a promise).

“exception” is a value that is thrown using the throw statement.

“reason” is a value that indicates why a promise was rejected.

由以上规范的描述可知, promise 是一个具有 then() 方法的对象

具体实现

下面是按照 Promises/A+ 规范来实现的 promise 方法:

 //定义 promise 的三种状态,这三种状态之间是互斥的
const PENDING = 'pending' //还在执行或者挂起状态
const FULFILLED = 'fulfilled' //执行成功状态
const REJECTED = 'rejected' //执行失败状态

//判断一个值是否是 promise
function isPromiseLike(value) {
   //根据 promise/A+ 规范判断传入的值是否是对象/函数,并且它是否具有 then 方法
   if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
      return value.then && typeof value.then === 'function'
   }
   return false
}

//模拟微任务,将 promise 执行的回调放入微任务队列中
function microTask(callback) {
   //判断浏览器环境
   if (MutationObserver && typeof MutationObserver === 'function') {
      const tag = 'div'
      const ob = new MutationObserver(callback)
      const el = document.createElement(tag)
      ob.observe(el, { attributes: true })
      el.dataset.name = tag
   }
   //判断 node 环境
   else if (process && typeof process === 'object' && typeof process.nextTick === 'function') {
      process.nextTick(callback)
   }
   //其他环境
   else {
      setTimeout(callback, 0)
   }
}

function myPromise(executor) {

   //这里通过闭包来模拟私有属性
   let state = PENDING //promise 的初始状态设置为 'pending'
   let result = undefined //promise 的初始结果不确定,设置为 undefined
   const handlers = [] //promise 的 then 方法中收集相关传入参数的数组集合

   // promise 改变状态的方法
   const stateChange = (next, value) => {
      //根据 promise/A+ 规范,promise 状态一旦改变,就确定下来不会再变化了
      //这里对 state 进行判断,防止重复触发改变 promise 的状态
      if (state !== PENDING) return
      state = next
      result = value
      //当状态变化时执行此方法
      onStateChange()
   }
   //promise 成功回调
   const resolve = (value) => {
      stateChange(FULFILLED, value)
   }

   //promise 失败回调
   const reject = (reason) => {
      stateChange(REJECTED, reason)
   }

   //当 promise 状态发生改变时执行的方法
   const handleStateChange = (callback, resolve, reject) => {
      //这里执行 then 方法中传入的参数要分三种情况:
      //1.传入的参数是函数 2.传入的参数是 promise 3.传入的参数不是函数
      microTask(() => {
            if (callback && typeof callback === 'function') {
               try {
                  //这里使用 try / catch 处理前两种情况
                  //将promise的执行结果传入回调函数中,获取回调函数的返回结果
                  const res = callback(result)
                  //判断结果是否是 promise
                  if (isPromiseLike(res)) {
                        //是 promise 则调用它的 then 方法
                        res.then(resolve, reject)
                  } else {
                        //不是 promise 则直接将结果 resolve
                        resolve(res)
                  }
               } catch (error) {
                  //在这里捕获回调执行的错误情况
                  reject(error)
               }
            } else {
               //这里处理传入参数不是函数/不是promise的情况
               const handler = state === FULFILLED ? resolve : reject
               handler(result)
            }
      })
   }

   //promise 状态变化执行的方法
   const onStateChange = () => {
      //如果 promise 的状态还在执行,没有发生变化,就不应该触发 then 方法的回调
      if (state === PENDING) return
      //通过 while 循环从 保存 then 方法的相关参数的集合中取出每一个参数集合执行 
      //这里因为 then 方法可以支持链式调用,所以用数组来存储,通过遍历来取出
      while (handlers.length > 0) {
            const { onFulfilled, onRejected, resolve, reject } = handlers.shift()
            //当 promise 执行成功,状态改变为 'fulfilled' 时
            if (state === FULFILLED) {
               handleStateChange(onFulfilled, resolve, reject)
            }
            //当 promise 执行失败,状态改变为 'rejected' 时
            else if (state === REJECTED) {
               handleStateChange(onRejected, resolve, reject)
            }
      }
   }

   try {
      executor(resolve, reject)
   } catch (error) {
      reject(error)
   }

   //promise 的 then 方法,这里是关键,根据 promise/A+ 规范 then 必须返回一个 promise
   this.then = function (onFulfilled, onRejected) {
      return new myPromise((resolve, reject) => {
            //这里由于我们无法确定 promise 在什么时候能完成(即不知道 promise 的状态在何时发生改变),
            //所以将 then 方法中的相关回调函数全部收集起来,等待状态变更时调用
            handlers.push({
               onFulfilled,
               onRejected,
               resolve,
               reject
            })
            //promise 状态变更时会执行此方法的逻辑
            onStateChange()
      })
   }
   
   //catch 方法实际上是只穿传入了 onRejected 的 then 方法
   this.catch = function (onRejected) {
      return this.then(undefined, onRejected)
   }
   
   //finally 方法没有参数,并且返回一个与原 promise 状态相同的 promise 对象
   this.finally = function (callback) {
      return this.then(
            (value) => {
               return myPromise.resolve(callback()).then(() => {
                  return value
               })
            },
            (reason) => {
               return myPromise.resolve(callback()).then(() => {
                  throw reason
               })
            }
      )
   }
}
//myPromise 的静态方法 resolve
myPromise.resolve = function (value) {
   return new myPromise((resolve, reject) => {
      if (isPromiseLike(value)) {
            value.then(resolve, reject)
      } else {
            resolve(value)
      }
   })
}

//myPromise 的静态方法 reject
myPromise.reject = function (reason) {
   return new myPromise((_, reject) => {
      reject(reason)
   })
}
//使用
const p = new myPromise((resolve, reject) => {
   resolve(1)
   //setTimeout(() => resolve(1), 1000)
})

p.then(
   (res) => {
      console.log('ok', res)
      return 123
   }
).then(
   (res) => {
      console.log('ok', res)
      return res * 2
   }
).then(123, (err) => {
   console.log('error', err)
}).then(
   (res) => {
      console.log('ok', res)
      return res * 2
   },
)

//输出:
// ok 1
// ok 123
// ok 246