• Promise 解决 Vue 中父子组件的加载问题!


    前言

    在这里插入图片描述

    关于Promie我这里就不多解释了,不懂得可以看看官方文档。下面文章重点介绍项目中遇到的问题解决方法。

    需求

    组件b初始化某个用到的库,只有在初始化完成后才能调用其API,不然会报错。a页面负责调用。

    // a.vue
    <template>
      <div>
        这是a页面
        <childB ref="childB" />
      </div>
    </template>
    <script>
    import childB from './b'
    export default {
      mounted() {
        setTimeout(() => {
          this.$refs.childB.play()
        }, 3000)
      },
      components: {
        childB,
      },
    }
    </script>
    // b.vue
    <template>
      <div>这是b页面</div>
    </template>
    <script>
    export default {
      data() {
        return {
          flag: false,
        }
      },
      created() {
        this.init()
      },
      methods: {
        init() {
          setTimeout(() => {
            this.flag = true
          }, 2000)
        },
        play() {
          if (!this.flag) return console.log('not init')
          console.log('ok')
        },
      },
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    以上代码为模拟初始化,用setTimeout代替,实际开发中使用是一个回调函数,那么我页面a也是用setTimeout?写个5秒?10秒?有没有解决方案呢?

    解决方案

    // a.vue
    <template>
      <div>
        这是a页面
        <childB ref="childB" />
      </div>
    </template>
    <script>
    import childB from './b'
    export default {
      mounted() {
        this.init()
      },
      methods: {
        init() {
          setTimeout(() => {
            this.$refs.childB.play()
          }, 2000)
        },
      },
      components: {
        childB,
      },
    }
    </script>
    // b.vue
    <template>
      <div>这是b页面</div>
    </template>
    <script>
    export default {
      methods: {
        play() {
          console.log('ok')
        },
      },
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    相信这也是最常见也是大多数人使用的方案了,但是我觉得把b组件中的代码写到了a页面中,假如有多个b组件,那么a页面中要写多好的b组件代码。容易造成代码混淆、冗余,发生异常的错误,阻塞进程,这显然是不能接受的。

    思考

    我们能不能用promise来告诉我们是否已经完成初始呢?

    答案当然是可以的!

    // a.vue
    <template>
      <div>
        这是a页面
        <childB ref="childB" />
      </div>
    </template>
    <script>
    import childB from './b'
    export default {
      mounted() {
        const { init, play } = this.$refs.childB
        init().then(play)
      },
      components: {
        childB,
      },
    }
    </script>
    // b.vue
    <template>
      <div>这是b页面</div>
    </template>
    <script>
    export default {
      methods: {
        init() {
          return new Promise(resolve => {
            setTimeout(() => {
              resolve()
            }, 2000)
          })
        },
        play() {
          console.log('ok')
        },
      },
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    不足

    init在a页面mounted时候才触发,感觉太晚了。能不能在b组件created时候自行触发呢?

    哈哈,当然可以了!

    // a.vue
    <template>
      <div>
        这是a页面
        <childB ref="childB" />
      </div>
    </template>
    <script>
    import childB from './b'
    
    export default {
      mounted() {
        this.$refs.childB.play()
      },
      components: {
        childB,
      },
    }
    </script>
    // b.vue
    <template>
      <div>这是b页面</div>
    </template>
    <script>
    function getPromiseWait() {
      let success, fail
      const promise = new Promise((resolve, reject) => {
        success = resolve
        fail = reject
      })
      return { promise, resolve: success, reject: fail }
    }
    const { promise, resolve } = getPromiseWait()
    export default {
      created() {
        this.init()
      },
      methods: {
        init() {
          setTimeout(() => {
            resolve('hello')
          }, 2000)
        },
        async play() {
          const res = await promise
          console.log('ok', res)
        },
      },
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    完美

    我们在b组件中生成一个promise来控制是否init完成,a页面只需要直接调用b组件的play方法即可。如有需要还可以在resolve传递参数,通过then回调函授拿到数据,Promise。

  • 相关阅读:
    Python机器学习分类算法(二)-- 决策树(Decision Tree)
    【性能测试】中间件优化
    从键入网址到网页显示的详细过程
    Elasticsearch面试题(查漏补缺)
    Python实现MYSQL蜜罐
    ES6面试题总结
    一行命令找出 Linux 中所有真实用户
    【AI】《动手学-深度学习-PyTorch版》笔记(二十一):目标检测
    图数据挖掘:基于概率的流行病模型
    Redis学习笔记①基础篇_Redis快速入门
  • 原文地址:https://blog.csdn.net/qq_41961239/article/details/132675122