eventBus是在vue中经常用来解决跨组件消息传递的问题,但对它的使用要特别注意,否则会产生很严重的后果。

引入

本文介绍了eventBus的实现原理,并介绍它如何在vue中使用,并举了一个具体的例子来说明,如果使用不当,它会造成内存泄漏。

要注意eventBus并不是前端的概念。

由greenrobot [1] 组织贡献(该组织还贡献了greenDAO),一个Android事件发布/订阅轻量级框架,

功能:通过解耦发布者和订阅者简化Android事件传递 [2]

EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,执行方法。

特点:代码简洁,是一种发布订阅设计模式(观察者设计模式)。

摘自百度百科。https://baike.baidu.com/item/EventBus/20461274?fr=aladdin

内容

  • eventBus在vue中的实现;

  • 在vue使用eventBus;

  • 使用不当的问题:多次执行回调;内存泄漏;

  • 解决方案:及时调用$off

eventBus在vue中的实现

eventBus是事件总线的意思,它本质上是一个发布订阅者实现,在vue2.X中,vue实例上提供了$on,$emit,$off这三个方法,分别用来添加观察者,发布事件,取消订阅这三个操作。

所以,我们可以直接把一个vue实例挂到Vue的原型上来充当组件相互通信的中介。

 Vue.prototype.$eventBus = new Vue()

这样一来,所有的Vue组件都可以沿着原型链找到这个$eventBus,从而访问$on, $off,$emit。

它可以帮助我们实现跨组件的通信。

例子:使用eventBus

在根组件中发布事件,在两个子组件中去监听事件。

 <div id="app">  <h2>eventBus的基本使用h2>  <com1>com1>  <com2>com2>div><script>  Vue.prototype.$eventBus = new Vue()  Vue.component('com1', {    template:`
com1

`,    created () {      this.$eventBus.$on('event1', function f1(d){        console.log(d, 'com1 listen... event1')     })   }, })  Vue.component('com2', {    template:`

com2

`,    created () {      this.$eventBus.$on('event2', function f2(d) {        console.log(d, 'com2 listen... event2')     })   } })  var vm = new Vue({    el: '#app',    created () {      setInterval( () => {        const d = Date.now()        this.$eventBus.$emit('event1', d)        this.$eventBus.$emit('event2', d)     }, 3000)   } })script>

在创建com1组件时,订阅event1事件;在创建com2组件时,订阅event2事件;在创建根组件(vue实例)时,开启定时器:每隔3s发布事件,这样的话,com1和com2就都可以收到事件,并执行对应的回调。

效果如下:

例子:不及时取消订阅

如果不及时取消订阅,则回调函数仍会执行,更严重的是,如果在事件处理回调函数中引用了外部变量形成了闭包,则会导致内存泄漏。

下面的代码说明这个问题。

在根组件(vue实例)中,补充一个数据项showCom1,并配置v-if指令来实现销毁和重建com1组件。

 <div id="app">  <h2>不及时取消订阅的问题h2>  <button @click="showCom1=!showCom1">    {{showCom1 ? "销毁" : "重建"}}组件1  button>  <com1 v-if="showCom1">com1>  <com2>com2>div><script>  Vue.prototype.$eventBus = new Vue()  Vue.component('com1', {    template:`
com1

`,    created () {      console.log('创建com1')      this.$eventBus.$on('event1', function f1(d) {        console.log(d, 'com1 listen... event1')     })   } })  Vue.component('com2', {    template:`

com2

`,    created () {      this.$eventBus.$on('event2', function f2(d) {        console.log(d, 'com2 listen... event2')     })   } })  var vm = new Vue({    el: '#app',    data:{      showCom1: true   },    created () {      setInterval( () => {        const d = Date.now()        this.$eventBus.$emit('event1', d)        this.$eventBus.$emit('event2', d)     }, 3000)   } })script>

先提一个问题:你觉得com1组件被销毁后,它在created中订阅的event1事件还能再收到吗?对应的回调函数还能再执行吗?一般的想法是组件都销毁了,那它订阅的事件肯定也收不到了嘛

答案是:还能收到。原因很简单:事件订阅这功能是$eventBus对象完成的,与这个com1组件无关。

上面的代码执行的效果,是这样的:

  • 销毁组件1之后,它还能正常收到event1事件,并执行回调;

  • 再次创建组件1后,它会再次订阅event1事件,所以结果是执行两次回调。

下面再来说明内存泄漏的问题,把com1的组件内容改成如下:

 Vue.component('com1', {  template:`
com1

`,  created () {    console.log('创建com1')    let m = 1*1024 * 1024    let arr = new Array(m).fill('a')    this.$eventBus.$on('event1', function f1(d) {      // 注意这里有一个闭包      console.log(d, 'com1 listen... event1', arr[1])   }) }})

在回调函数f1中引用函数之外的变量arr,这里有一个闭包。

下面在浏览器的调试工具中的memory添加一个快照,查看结果如下:

然后,点击页面上的“销毁组件1”,再次添加一个快照,你会发现这个空间并没有释放掉。

解释如下:

上面是这个过程的示意图,由于没有及时取消订阅f1,所以arr这个数组并没有释放掉。

解决方案:

在com1的destoryed钩子中,调用$off来取消订阅。

 destroyed () {  // 取消所有对event1事件的监听  this.$eventBus.$off('event1')}

调试结果如下:

可见,com1删除之后,这个数值的空间释放掉了,同时它的事件监听函数也不会再执行了。

其它注意事项

$off的格式:

  • $off() 会取消所有的事件订阅;

  • $off('事件名') 会取消指定事件名的;

  • $off('事件名', 回调) 会取消指定事件名的,指定回调

父子组件的created和mounted的区别, 按执行顺序:

  • 父组件的created 先于子组件的created

  • 父组件的mounted先于子组件的mounted

所以,到底在哪个钩子中订阅,在哪个钩子中发布,要根据情况来定。

小结

eventBus是一个名词,并非前端独有;

new Vue() 得到的实例上已经实现了发布订阅模式,可以直接做eventBus使用;

使用eventBus要及时调用$off;

版权信息:凡人进阶。转载请标明出处。如果对您有帮助,您可以:

  • 转发他人。

  • 小额打赏。

  • 关注本号。

vue created 调用方法_vue中的eventBus会产生内存泄漏吗相关推荐

  1. vue 关闭弹如何销毁子组件_vue中的eventBus会产生内存泄漏吗

    eventBus是在vue中经常用来解决跨组件消息传递的问题,但对它的使用要特别注意,否则会产生很严重的后果. 引入 本文介绍了eventBus的实现原理,并介绍它如何在vue中使用,并举了一个具体的 ...

  2. vue created 调用方法_vue 基础-生命周期 lifecycle 的执行顺序和作用

    前言 <vue 基础>系列是再次回炉 vue 记的笔记,除了官网那部分知识点外,还会加入自己的一些理解.(里面会有部分和官网相同的文案,有经验的同学择感兴趣的阅读) 平时开发中,我真的不太 ...

  3. vue created 调用方法_深入解析 Vue 的热更新原理,偷学尤大的秘籍?

    大家都用过 Vue-CLI 创建 vue 应用,在开发的时候我们修改了 vue 文件,保存了文件,浏览器上就自动更新出我们写的组件内容,非常的顺滑流畅,大大提高了开发效率.想知道这背后是怎么实现的吗, ...

  4. vue中解决three.js出现内存泄漏丢失上下文问题

    vue中解决three.js出现内存泄漏丢失上下文问题 参考文章: (1)vue中解决three.js出现内存泄漏丢失上下文问题 (2)https://www.cnblogs.com/lichuank ...

  5. iOS中滤镜处理及相关内存泄漏问题的解决

    iOS中滤镜处理及相关内存泄漏问题的解决 参考文章: (1)iOS中滤镜处理及相关内存泄漏问题的解决 (2)https://www.cnblogs.com/ToBeTheOne/p/5708906.h ...

  6. vue组件穿方法_vue组件中的数据传递方法

    Vue 的组件作用域都是孤立的,不允许在子组件的模板内直接引用父组件的数据.必须使用特定的方法才能实现组件之间的数据传递.组件之间传递数据大致分为三种情况: 父组件向子组件传递数据,通过 props ...

  7. vue暴露的全局方法_Vue中实现全局方法

    内心背景:今天偶然上到论坛,看到关于Vue的两篇阅读量破千,我TM膨胀了啊.赶快再写一篇我开始用Vue时遇到的问题. 现实背景:很多时候我们会在全局调用一些方法. 实现方式两种:官网的实现use方法, ...

  8. vue修改meta值_vue中动态设置meta标签和title标签的方法

    vue中动态设置meta标签和title标签的方法 因为和原生的交互是需要h5这边来提供meta标签的来是来判断要不要显示分享按钮,所有就需要手动设置meta标签,标题和内容 //router内的设置 ...

  9. vue组件穿方法_vue组件间通信六种方式(完整版)

    [51CTO.com原创稿件] 前言 组件是 vue.js强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系: 如上图所示,A ...

最新文章

  1. EMC开发实习生电面经验
  2. 粒子滤波Matlab示例
  3. 自学架构设计的一个好方法
  4. 【BOM is recursion】BOM 是递归的
  5. springnbsp;security总结nbsp;太有用了!!
  6. 产品小白的知识点1——用户周期
  7. 谷歌网络代理工具_谷歌更新了Dialogflow AI引擎,帮助客户创建更好的虚拟代理...
  8. windows删除文件c语言函数,c rename()函数是否删除文件?
  9. 利用IP标准访问列表进行网络流量的控制
  10. 用matlab计算基金收益,CAPM模型计算的MATLAB实现
  11. html班级主题完整代码,HTML班级网站
  12. yum源解释(接地气)
  13. js-最常用的js表单校验1
  14. 基于Android开发的手持扫码枪APP(附带参考源码)
  15. 使用openCV进行视频人脸识别
  16. CP-ABE方案形式化定义及安全模型总结
  17. 网站关键词优化的五点原则
  18. 2011年1月13日抓取的QQ空间报错信息
  19. 管家婆辉煌版密码遗忘处理
  20. WPF 捕获键盘输入事件

热门文章

  1. java如何测controller层_用MockMvc对Spring mvc中的controller层进行单元测试
  2. KubeSphere中部署Minio服务
  3. Python中fastapi构建的web项目配置环境变量
  4. vue 调用webservice_调用webService的几种方式
  5. html table 转置,jQuery+CSS实现的table表格行列转置功能示例
  6. java正则表达式所有字符串_“JAVA”正则表达式如何匹配所有符合要求的子字符串?...
  7. 使用JasperReport 引擎PDF报表,因为iText版本升级,由原来的包名com.lowagie.text.pdf.fonts转化为com.itextpdf.text.pdf.fonts
  8. List中的每个元素,两两为一对(不包括自身)组合
  9. Java操作某方法时报错:java.lang.NoSuchMethodError
  10. 微服务RPC框架-Feign