阅读 159

手写一个promise终结(一)

microsoft-edge-TcC5qr3dpgA-unsplash.jpg

手写一个promise,我已经记不清看了多少个版本了。但却没有自己手敲一遍,自己写一个。昨晚跟同事摆头 他说简单得嘞,我让他现场写一个,好家伙 写到后面 promise怎么用都不会了 不过还是强的 最后写出来了。趁还有热度 自己总结一波吧

一、先到MDN细致回顾一遍 promise到底有哪些使用方法

普及一下: promise没有源码,它的底层的浏览器v8已经实现好的。实际是通过c++实现的

二、脑海里构建出 promise该有的结构

      class myPromise {
        constructor () {
          this.status = 'pending'
        }
        then () {}
        catch () {}
        finally () {}
        all () {}
        /**
         * allSettled 不常用
         *  等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。
            返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。
        */
        allSettled () { }
        any () {}
        race () {}
        reject () {}
        resolve () {}
      }
复制代码

基本结构已经出来了, 我们先new 一个promise看看是个啥子

      const p = new Promise((resolve, reject) => {

      })
      console.log(p)
复制代码

image.png

是个pending状态的Promise,只有当我们resolve的时候才会变成fulfilled状态,当我们调用reject的时候变成rejected状态

---好家伙这个state怎么长这样的。。。 好吧 根据它的打印结果先定义好构造函数

    constructor (handle) {
          this['[[PromiseState]]'] = 'pending'
          this['[[PromiseResult]]'] = undefined
        }
复制代码

三、解析实现

1、new 一个promis实例的时候,给promise传入了一个函数,所以我们要在promise中接收一个函数(handle),该函数里面又包含了一个resolve函数调用,一个reject函数调用,所以handle还有两个函数参数

2、根据上面打印出来的结果可以知道 当我们在外部resolve或者reject的时候,要改变promiseState,以及要把结果集放入PromiseResult中

      class myPromise {
        constructor (handle) {
          this['[[PromiseState]]'] = 'pending'
          this['[[PromiseResult]]'] = undefined
          handle((res) => {
            this['[[PromiseState]]'] = 'fulfilled'
            this['[[PromiseResult]]'] = res
          }, (err) => {
            this['[[PromiseState]]'] = 'rejected'
            this['[[PromiseResult]]'] = err
          }) // 传递过来立即执行
        }
        then () {}
        catch () {}
        finally () {}
        all () {}
        /**
         * allSettled 不常用
         *  等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。
            返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。
        */
        allSettled () { }
        any () {}
        race () {}
        reject () {}
        resolve () {}
      }
      const myP = new myPromise((resolve, reject) => {

      })
      console.log('myP', myP)
复制代码

image.png ----嗯 有内味了

then

3、接下来我们去康康then. then原来接收两个回调函数,好家伙 在日常开发中都习惯了把错误信息reject到catch中

        then (successCallback, failCallback) {
          if (this['[[PromiseState]]'] === 'fulfilled') {
            successCallback && successCallback(this['[[PromiseResult]]'])
          } else {
            failCallback && failCallback(this['[[PromiseResult]]'])
          }
        }
复制代码

----我这样纸写then是可以执行resolve ,reject的但是我加上setTimeout就啥也不是了。 这样子写then其实是个立即执行函数。所以还得改造一下

4、不能给他立即执行, 所以可以先把回调函数存储起来,然后在resolve,或者reject的时候再去执行回调

---注:只有在调取了resolve或者reject之后才执行回调函数---

 class myPromise {
        constructor (handle) {
          this['[[PromiseState]]'] = 'pending'
          this['[[PromiseResult]]'] = undefined
          this.resolveFn = undefined
          this.rejectFn = undefined
          handle(this.#resolve.bind(this), this.#reject.bind(this)) //
        }
        /**
         * 为了方便维护,我把resolve与reject作为内部函数
        */
        #resolve (val) {
          this['[[PromiseState]]'] = 'fulfilled'
          this['[[PromiseResult]]'] = val
          console.log('this.resolveFn', this.resolveFn)
          this.resolveFn(val)
        }
        #reject (err) {
          this['[[PromiseState]]'] = 'rejected'
          this['[[PromiseResult]]'] = err
          this.rejectFn(err)
        }
        then (successCallback, failCallback) {
          this.resolveFn = successCallback
          this.rejectFn = failCallback
        }
     }
      const myP = new myPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('jdjkkjdd')
        }, 1000)
      })
      myP.then(res => {
        console.log('res', res)
      })
      console.log('myP', myP)
复制代码

5、接下来聊一聊多个then,不是链式的多个then

      const p = new Promise((resolve, reject) => {
          resolve('resulr')
      })
      p.then(res => {
        setTimeout(() => {
          console.log('111', res)
        }, 1000)
      }, err => {
        console.log(err)
      })
      p.then(res => {
        console.log('2222',res)
      })
      console.log(p)
     // ...
     //是类似这种的多个then
复制代码

image.png

---结果是不是还是很正常的 因为我111加了setTimeout
但是我们写的promise只会执行最后一次的,为啥呢??
因为我们定义的this['[[PromiseResult]]']会被覆盖掉。所以我们要把resolveFn、rejectFn变成数组的形式 把回调函数都保存起来

 class myPromise {
        constructor (handle) {
          this['[[PromiseState]]'] = 'pending'
          this['[[PromiseResult]]'] = undefined
          this.resolveFn = []
          this.rejectFn = []
          handle(this.#resolve.bind(this), this.#reject.bind(this)) //
        }
        /**
         * 为了方便维护,我把resolve与reject作为内部函数
        */
        #resolve (val) {
          this['[[PromiseState]]'] = 'fulfilled'
          this['[[PromiseResult]]'] = val
          // this.resolveFn && this.resolveFn(val)
          // 从尾推入, 从头拿出
          const run = () => {
            let cb
            while (cb = this.resolveFn.shift()) {
              cb && cb(val)
            }
          }
          run()
        }
        #reject (err) {
          this['[[PromiseState]]'] = 'rejected'
          this['[[PromiseResult]]'] = err
          // this.rejectFn && this.rejectFn(err)
          // 从尾推入, 从头拿出
          const run = () => {
            let cb
            while (cb = this.rejectFn.shift()) {
              cb && cb(err)
            }
          }
          run()
        }
        then (successCallback, failCallback) {
          this.resolveFn.push(successCallback)
          this.rejectFn.push(failCallback)
        }
     }
      const myP = new myPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('jdjkkjdd')
        }, 1000)
      })
      myP.then(res => {
        console.log('res', res)
      })
      myP.then(res => {
        console.log('2222', res)
      })
      console.log('myP', myP)
复制代码

我不行了 休息一会儿。promise太难搞了,,,,好看记得一键三连哦~ 后期会继续更新完成

文章分类
前端
文章标签