Shaoli's Blog

一、手写源码之 Promise

用构造函数尝试实现,代码如下:


 const [PENDING, FULFILLED, REJECTED] = ['pending''fulfilled''rejected']
 function NewPromise(fn{
   this.state = PENDING


   this.result = undefined
   this.reason = undefined


   this.resolvedCbs = []
   this.rejectedCbs = []


   const resolve = (val) => {
     if(this.state === PENDING) {
       this.state = FULFILLED
       this.result = val
       this.resolvedCbs.forEach(fn => fn())
     }
   }


   const rejected = (val) => {
     if(this.state === PENDING) {
       this.state = REJECTED
       this.reason = val
       this.rejectedCbs.forEach(fn => fn())
     }
   }


   try {
     fn(resolve, rejected)
   } catch (error) {
     rejected(error)
   }
 }


 NewPromise.prototype.then = function(onFulfilled, onRejected = (e) => throw e }) {
   return new NewPromise((resolve, reject) => {
     if(!onFulfilled instanceof Function) {
       onFulfilled = result => result
     }


     function handle(cb{
       try {
         cb()
       } catch (e) {
         reject(e)
       }
     }


     if(this.state === PENDING) {
       this.resolvedCbs.push(() => {
         handle(() => {
           const r = onFulfilled(this.result)
           resolve(r)
         })
       })
       this.rejectedCbs.push(() => {
         handle(() => {
           const r = onRejected(this.reason)
           resolve(r)
         })
       })
     }
     if(this.state === FULFILLED) {
       handle(() => {
         const r = onFulfilled(this.result)
         resolve(r)
       })
     }
     if(this.state === REJECTED) {
       handle(() => {
         const r = onRejected(this.reason)
         resolve(r)
       })
     }
   })
 }


 NewPromise.prototype.catch = function(onRejected{
   return this.then(undefined, onRejected)
 }

NewPromise.prototype.all = function(cbs{
  let count = 0
  const len = cbs.length
  const arr = []
  cbs.forEach((p => {
    p.then((r) => {
      arr.push(r)
      count++
      if(len === count) {
        resolve(arr)
      }
    }).catch(e => {
      reject(e)
    })
  }))
}


NewPromise.prototype.race = function(cbs{
  const len = cbs.length
  cbs.forEach((p => {
    p.then((r) => {
      resolve(r)
    }).catch(e => {
      reject(e)
    })
  }))
}



执行试试,达到了预期效果,完美!

new NewPromise((resolve, reject) => {
  console.log('in Promise...')
  resolve(111)
}).then((val) => {
  console.log('resolve👉', val)
}, (e) => {
  console.log('rejected😖', e)
})


  new NewPromise((resolve, reject) => {
    console.log(11111111)
    reject(1)
  }).then((val) => {
    console.log('resolve',val)
  }).catch((e) => {
    console.log('reject', e)
  })


 const p1 = new NewPromise((resolve, reject) => {
   reject(1)
 })

 const p2 = new NewPromise((resolve, reject) => {
   resolve(2)
 })

 p1.then((val) => {
   console.log('resolve1',val)
 }).catch((e) => {
   console.log('reject1', e)
 })

 p2.then((val) => {
   console.log('resolve2',val)
 }).catch((e) => {
   console.log('reject2', e)
 })




还有一种版本是 class写法的,相比构造函数会难写些。


class MyPromise {
  constructor (fn) {
    this.state = 'pending'
    this.value = undefined
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    let reject = value => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.value = value
      }
    }
    // 自动执行函数
    try {
      fn(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  // then
  then(onFulfilled, onRejected) {
    switch (this.state) {
      case 'fulfilled':
        onFulfilled(this.value)
        break
      case 'rejected':
        onRejected(this.value)
        break
      default:
        onRejected(this.value);
    }
  }
}


这边判断了 state === pending ,是因为防止 多个 resolve 、多个 reject 或 resolve 和 reject 混用时,会执行多次回调。
# 如果不加判断,以下所有的resolve和reject都会执行,返回值为最后一个回调值。
if (this.state === 'pending') {}

new MyPromise((resolve, reject) => {
  console.log('in Promise...')
  resolve(111)
  resolve(222)
  reject(333)
})


如有不足,请指出!🤝

    评论列表

  • 暂无评论...快来说说吧!
person
0 / 16
comment
0 / 100