看我如何用 Promise 解决 Vue 中父子组件的加载问题!

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

举个例子

需求

组件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>

复制代码

以上代码为模拟初始化,用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>
复制代码

相信这也是最常见也是大多数人使用的方案了,但是我觉得把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>
复制代码

嗯~ o( ̄▽ ̄)o 果然nice,干净整洁,一气呵成!

不足

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>

复制代码

完美

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

作者:𝓼𝓹𝓻𝓲𝓽𝓮𝓐𝓹𝓮
链接:https://juejin.cn/post/7225127360445841466
来源:稀土掘金

Node 社群

 
 

我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

e877a42e3e0376dca0f7ca44cb08e5f9.png

“分享、点赞、在看” 支持一下
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值