手写一个promise终结(二)

929 阅读6分钟

上次分析到了多个then调用

还没有看上一篇文章的小伙伴可以先看上半部分,手写一个promise终结(一) - 掘金 (juejin.cn)

其实上次我是发现了我一直用setTimeout执行回调,结果把setTimeout去掉之后就啥也不是了。

        then (successCallback, failCallback) {
          if (this['[[PromiseState]]'] === 'fulfilled') {
            successCallback && successCallback(this['[[PromiseResult]]'])
          }  else if (this['[[PromiseState]]'] === 'rejected') {
            failCallback && failCallback(this['[[PromiseResult]]'])
          } else if (this['[[PromiseState]]'] === 'pending') {
            this.resolveFn.push(successCallback)
            this.rejectFn.push(failCallback)
          }
        }
      }
      const myP = new myPromise((resolve, reject) => {
        reject('err')
      })
      myP.then(res => {
        console.log('res', res)
      }, err => {
        console.log('err', err)
      })

我把then改造了一下, 就是根据它的状态去判断是否要立即执行还是存储。 其实还有一个办法就是把#resolve和#reject中的run()setTimeout一下 setTimeout( () => { run() })这样也可

┭┮﹏┭┮ 太难搞了, 我写那么多if判断搞啥子。日常开发中太多的if else 估计会被喷死的

      // 222 --- 333- 555 -- 444 --- 111 预期结果
      setTimeout (() => {
        console.log('1111')
      }, 2000)
      console.log('222')
      const myP = new myPromise((resolve, reject) => {
        console.log('333')
        resolve('suss')
      })
      myP.then(res => {
        console.log('444')
        console.log('res', res)
      }, err => {
        console.log('err', err)
      })
      console.log('5555')
      console.log('myP', myP)

image.png 结果却是这样的~, 为啥子呀,裂开。
由上可知,我的promise没有所谓的微、宏任务就是个同步的
因为我的promise resolve与then之间没有设置微、宏任务嘛 所以还是得 setTimeout( () => { run() }),但是更确切的应该是微任务的写法

          const observer = new MutationObserver(run)
          observer.observe(document.body, {
            attributes: true
          })
          document.body.setAttribute('what', 'shenmewanyier')

这个小插曲结束了, 下面继续

6、链式调用。一般情况下链式调用的关键是 return this 但是如果这里返回一个return this 的话就会出现每次链式之间好像都没有什么关联, 永远返回的是new 出来的实例, 所以要每次都返回一个新的promise

        then (successCallback, failCallback) {
          return new myPromise ((resolve, reject) => {
            let resolveFn = (res) => {
              let val = successCallback && successCallback(res) // 拿到回调函数的执行结果
              resolve(val)
            }
            this.resolveFn.push(resolveFn)

            let rejectFn = (res) => {
              let val = failCallback && failCallback(res)
              reject(val)
            }
            this.rejectFn.push(rejectFn)
          })
        }
        
      const myP = new myPromise((resolve, reject) => {
        resolve('suss')
      })
      myP.then(res => {
        console.log('res', res)
        return 'fhfh'
      }).then(res => {
        console.log('122', res)
      })

image.png

现在我们只能处理return一个普通值的情况,promise其实还可以return 一个promise, 咋整。 那就是去取promise。then返回的值就差不多了

        then (successCallback, failCallback) {
          return new myPromise ((resolve, reject) => {
            let resolveFn = (res) => {
              let val = successCallback && successCallback(res) // 拿到回调函数的执行结果
              // 判断val的类型
              if (val instanceof myPromise) {
                // val.then(a => {
                //   resolve(a)
                // })
                val.then(resolve)
              } else {
                resolve(val)
              }
            }
            this.resolveFn.push(resolveFn)

            let rejectFn = (res) => {
              let val = failCallback && failCallback(res)
              reject(val)
            }
            this.rejectFn.push(rejectFn)
          })
        }

then 终于结束了,这东西太难搞了。加油继续奋起

后面有了解到catch、finally为原型方法, race、 all、allSettled、 resolve、 reject称为静态方法

catch

接下来我们讲讲catch, 其实catch我们上面在then中已经实现了, 所以我们在catch方法中重新调用一下then就可以了

        catch (fn) {
          return this.then(undefined, fn)
        }

resolve

我们先打印看看resolve之后会返回什么


      const p = Promise.resolve('success')
      console.log(p)

image.png 其实也是一个promise对象, 所以我们直接return一个promise给他就好
注意:resolve是一个静态方法

        static resolve (val) {
          return new myPromise (resolve => {
            resolve(val)
          })
        }

reject

reject跟resolve是一样的道理,直接上代码!

        static reject (err) {
          return new myPromise ((resolve, reject) => {
            reject(err)
          })
        }

race

race就是一个数组,只拿取最快得到的执行结果,就终止了

        static race (list) {
          return new myPromise((resolve, reject) => {
            list.forEach(element => {
              item.then(res => { // 谁最快,谁先调取
                resolve(res)
              }, err => {
                reject(err)
              })
            });
          })
        }

allSettled

allSettled与all的区别就是allSettled 不管成功还是失败都会去收集,而all只收集成功的结果

先来看一下allSettled 原有的样子吧


      const p = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('111')
        }, 1000)
      })
      const p2 = new Promise((resolve, reject) => {
          reject('222')
      })
      const p3 = new Promise((resolve, reject) => {
          resolve('333')
      })
      Promise.allSettled([p, p2, p3]).then(res => {
        console.log('allSettled', res)
      }, err => {
        console.log('allSettled err', err)
      })
      console.log(p)

image.png 所以该有的样子是一个数组,里面每个对象对应相应结果集,包含status,成功:value, 失败: reason。下面开始吧

        static allSettled (lists) {
          let resArr = new Array(lists.length) // lists的结果集要一一对应且长度相等
          let num = 0 // lists是否执行完毕
          return new myPromise( resolve => {
            lists.forEach((item, key) => {
              let obj = {}
              item.then(res => {
                obj['status'] = 'fulfilled'
                obj['value'] = res
                resArr[key] = obj
                num++
                if (num >= lists.length) {
                  resolve(resArr)
                }
              }, err => {
              obj['status'] = 'rejected'
              obj['reason'] = err
              resArr[key] = obj
              num++
              if (num >= lists.length) {
                  resolve(resArr)
              }
            })
            })
          })
         }
      const myP = new myPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('111')
        }, 1000)
      })
      const myP2 = new myPromise((resolve, reject) => {
        reject('222')
      })
      const myP3 = new myPromise((resolve, reject) => {
        resolve('332')
      })
      myPromise.allSettled([myP, myP2, myP3]).then(res => {
        console.log('结果', res)
      })

image.png allSettled 已经搞定了, 还差最后两个, finally、all, 渣油

all

all 就是碰到reject就停止收集,并且只返回错误结果, 如果都是成功就返回成功的list, 还是看看原有的样子吧

      const p = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('111')
        }, 1000)
      })
      const p2 = new Promise((resolve, reject) => {
          resolve('222')
      })
      const p3 = new Promise((resolve, reject) => {
          resolve('333')
      })
      Promise.all([p, p2, p3]).then(res => {
        console.log('allSettled', res)
      }, err => {
        console.log('err', err)
      })

image.png 动手吧!!

        static all (list) {
          let successArr = new Array(list.length) // 成功的结果集
          let flag = false // 是否有错误信息
          const length  = list.length
          return new myPromise((resolve, reject) => {
            for (let i = 0; i < length; i++ ) {
              list[i].then(res => {
                successArr[i] = res
                if (i >= list.length -1 && !flag) {
                  resolve(successArr)
                }
              }, err => {
                flag = true
                reject(err)
                return
              })
            }
          })
        }

image.png

finally

finally就是不管是resolve,还是reject都会去执行,且没有参数返回值。那不是搜搜搞定!!!

        finally (Callback) {
          if (this['[[PromiseState]]'] !== 'pending') {
            Callback && Callback()
          }
        }

终于结束了!最后附上完整代码

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)
            }
          }
          const observer = new MutationObserver(run)
          observer.observe(document.body, {
            attributes: true
          })
          document.body.setAttribute('what', 'shenmewanyier')
        }
        #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)
            }
          }
          const observer = new MutationObserver(run)
          observer.observe(document.body, {
            attributes: true
          })
          document.body.setAttribute('what', 'shenmewanyier')
        }
        then (successCallback, failCallback) {
          return new myPromise ((resolve, reject) => {
            let resolveFn = (res) => {
              let val = successCallback && successCallback(res) // 拿到回调函数的执行结果
              // 判断val的类型
              if (val instanceof myPromise) {
                // val.then(a => {
                //   resolve(a)
                // })
                val.then(resolve)
              } else {
                resolve(val)
              }
            }
            this.resolveFn.push(resolveFn)

            let rejectFn = (res) => {
              let val = failCallback && failCallback(res)
              reject(val)
            }
            this.rejectFn.push(rejectFn)
          })
        }
        catch (fn) {
          return this.then(undefined, fn)
        }
        finally (Callback) {
          if (this['[[PromiseState]]'] !== 'pending') {
            Callback && Callback()
          }
        }

        static all (list) {
          let successArr = new Array(list.length) // 成功的结果集
          let flag = false // 是否有错误信息
          const length  = list.length
          return new myPromise((resolve, reject) => {
            for (let i = 0; i < length; i++ ) {
              list[i].then(res => {
                successArr[i] = res
                if (i >= list.length -1 && !flag) {
                  resolve(successArr)
                }
              }, err => {
                flag = true
                reject(err)
                return
              })
            }
          })
        }
        /**
         * allSettled 不常用
         *  等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。
            返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。
        */
        static allSettled (lists) {
          let resArr = new Array(lists.length) // lists的结果集要一一对应且长度相等
          let num = 0 // lists是否执行完毕
          return new myPromise(resolve => {
            lists.forEach((item, key) => {
              let obj = {}
              item.then(res => {
                obj['status'] = 'fulfilled'
                obj['value'] = res
                resArr[key] = obj
                num++
                if (num >= lists.length) {
                  resolve(resArr)
                }
              }, err => {
              obj['status'] = 'rejected'
              obj['reason'] = err
              resArr[key] = obj
              num++
              if (num >= lists.length) {
                  resolve(resArr)
              }
            })
            })
          })
         }
        static race (list) {
          return new myPromise((resolve, reject) => {
            list.forEach(element => {
              element.then(res => { // 谁最快,谁先调取
                resolve(res)
              }, err => {
                reject(err)
              })
            });
          })
        }
        static reject (err) {
          return new myPromise ((resolve, reject) => {
            reject(err)
          })
        }
        static resolve (val) {
          return new myPromise (resolve => {
            resolve(val)
          })
        }
      }
      const myP = new myPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('111')
        }, 3000)
      })
      myP.finally(() => {
        console.log('结束')
      })
      const myP2 = new myPromise((resolve, reject) => {
        resolve('222')
      })
      const myP3 = new myPromise((resolve, reject) => {
        resolve('332')
      })