Vue依赖收集引发的问题
问题背景
在我们的项目中有一个可视化配置的模块,是通过go.js生成canvas来实现的。但是,我们发现这个模块在浏览器中经常会引起该tab页崩溃。开启chrome的任务管理器一看,进入该页面内存和cpu就会暴涨,内存经常会飙到700多M。但是我们的canvas实际的像素只有约500x500,根据一些粗略的计算,大概只占了1M的内存,这个计算过程可参考100*100的 canvas 占多少内存。那么我们这700M内存是哪里来的呢?
定位问题
我们可以使用chrome开发者工具来分析我们的调用栈。这边我是先通过Performance来帮助我们定位问题,它会帮我们生成一段过程中一些数据的变化,包括js堆内存、dom节点数量、动画帧等数据,如图:

这是切换至一个canvas画布较大的一个模块的performance分析表现,可以看到占用了472M的内存。下面折线图蓝色部分是js堆内存的变化,而Main下面黄色与紫色的矩形框就是我们的调用栈,上下两部分是按照时间一一对应的。可以看到,蓝色的折线呈高低起伏的态势,GC回收之后低点基本和高点持平,因此可以断定几乎不存在内存泄漏的问题。然后我们可以放大去看一看,内存升高的时候,js做了些什么事情,找一找规律。

我们随机找一段内存增长的区域,可以看到在内存增长的过程中,最为频繁调用的就是Observer相关的代码。但是就这么看,我们不能够明白Observer是在干什么。此时我们可以借用Memory选项中的Allocation Sampling按照javascript function来查看内存分配,我们同样录制以上的一段操作。

此时我们能够清楚的看到,的确是这个Observer在作怪。同时,我们可以看到这是vue的代码,点击右边的文件查看source code,就可以清楚的明白这就是vue在执行依赖收集的操作,此时会给属性添加watcher。那我们这里为什么会有如此多的属性被添加了watcher呢?看了一下代码,原来是我把go.js的一个实例挂到了vue的data选项中,放到data中的属性会被vue执行依赖收集的相关操作,而这个实例拥有非常多的嵌套属性,全部都会被添加watcher。其实,我们只是想单纯的存储一下这个实例,供我们后续调用其相关的方法,添加watcher对我们来说完全没有意义,那我们如何避免这样的问题呢?
解决问题
上网搜索了相关的解决方案,大概有如下几种:
- 在data中定义的属性前面加上$,即通知vue该属性不需要被依赖收集,例如:```javascript
data() {
return {
$goDiagram: null
}
}
2. 不在data中声明,直接在赋值的时候声明this.goDiagram = diagram。这同样会遇到第一种方案的问题,模板中会提示找不到goDiagram属性。
3. 不在data中声明,而是利用$options来存储goDiagram,例如:
```javascript
export default {
goDiagram: null,
mounted() {
this.$options.goDiagram = xxx
}
}
这应该是比较好的一个方法,vue官方中也说明了$options用来包含自定义属性,例如我们平时引入的常量或是枚举类型,我们也不希望它们被添加无意义的watcher,因此可以通过这种方式来定义,在template中引用时只需要{{$options.xxx}}即可。这种方式唯一的缺点就是不能像data那样一眼望去就能清楚地知道你定义了什么属性。
项目中我采用了第一种方式,经过修改后内存占用量减少到原来的1/5到1/6,可以说效果非常好,再也不会出现浏览器崩溃的情况了。
总结
通过这样的一个问题,我们主要能够学习到两点:
- 如何通过chrome的开发者工具,去快速地定位代码中存在的内存问题
- 不要盲目的将属性都挂载到data选项中,一些常量我们可以采取上面提到的几种方式来定义,以此来作为一种优化手段
Vue依赖收集引发的问题的更多相关文章
- 三、vue依赖收集
Vue 会把普通对象变成响应式对象,响应式对象 getter 相关的逻辑就是做依赖收集,这一节我们来详细分析这个过程 Dep Dep 是整个 getter 依赖收集的核心,它的定义在 src/core ...
- Vue 依赖收集原理分析
此文已由作者吴维伟授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Vue实例在初始化时,可以接受以下几类数据: 模板 初始化数据 传递给组件的属性值 computed wat ...
- Vue.js依赖收集
写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...
- 读Vue源码 (依赖收集与派发更新)
vue的依赖收集是定义在defineReactive方法中,通过Object.defineProperty来设置getter,红字部分主要做依赖收集,先判断了Dep.target如果有的情况会执行红字 ...
- 深入浅出Vue基于“依赖收集”的响应式原理(转)
add by zhj: 文章写的很通俗易懂,明白了Object.defineProperty的用法 原文:https://zhuanlan.zhihu.com/p/29318017 每当问到VueJS ...
- vue的双向绑定和依赖收集
在掘金上买了一个关于解读vue源码的小册,因为是付费的,所以还比较放心 在小册里看到了关于vue双向绑定和依赖收集的部分,总感觉有些怪怪的,然后就自己跟着敲了一遍. 敲完后,发现完全无法运行, 坑啊 ...
- 【Vue源码学习】依赖收集
前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...
- 使用 Proxy + Promise 实现 依赖收集
(深入浅出Vue基于“依赖收集”的响应式原理) ,这篇文章讲的是通过一个通俗易懂例子,介绍了 如何用Object.defineProperty 实现的“依赖收集”的原理.Object.definePr ...
- Vue一个案例引发「内容分发slot」的最全总结
今天我们继续来说说 Vue,目前一直在自学 Vue 然后也开始做一个项目实战,我一直认为在实战中去发现问题然后解决问题的学习方式是最好的,所以我在学习一些 Vue 的理论之后,就开始自己利用业余时间做 ...
随机推荐
- 网络编程-SOCKET开发之----2. TCP粘包现象产生分析
1. 粘包现象及产生原因 1)概念 指TCP协议中,发送方发送的若干个包数据到接收方接收时粘成一包.发送方粘包:发送方把若干个要发送的数据包封装成一个包,一次性发送,减少网络IO延迟:接收方粘包:接收 ...
- 953.Verifying an Alien Dictionary(Map)
In an alien language, surprisingly they also use english lowercase letters, but possibly in a differ ...
- BZOJ 4665
orz gery 一发rk1真有趣(其实我没想着常数优化 inline int sqr(int x){return 1ll*x*x%mo;} const int N=2011; int n,a[N], ...
- CGI、FastCGI、PHP-FPM联系与区别(理解总结自其他博文)
参考:http://blog.csdn.net/tyrantbear/article/details/52077321 参考:http://mp.weixin.qq.com/s?src=11& ...
- vscode1.30.1使用的electron3.0.10中的bug
PS C:\GitHub\vscode2\vscode> scripts\code.bat[13:07:19] Syncronizing built-in extensions...[13:07 ...
- Java 将容器List里面的内容保存到数组
import java.util.List; import java.util.ArrayList; public class listToArr { public static void main( ...
- 机器学习(六)K-means聚类、密度聚类、层次聚类、谱聚类
本文主要简述聚类算法族.聚类算法与前面文章的算法不同,它们属于非监督学习. 1.K-means聚类 记k个簇中心,为\(\mu_{1}\),\(\mu_{2}\),...,\(\mu_{k}\),每个 ...
- vim 常用指令
其他命令 <c-L> 重绘屏幕 <c-z> 挂起vim回到shell,想继续vim只需要输入 fg <c-x-f> 文件路径提示 <c-N> 当前文件中 ...
- SecureCRT连接虚拟机失败及虚拟机ping不通外网
背景: VMware上安装了centos,从学校的网络换到了家里后,用SecureCRT登录时发现 connection closed,然后在虚拟机里发现ping不通外网了,ping虚拟机IP是通的. ...
- 初识CUDA
如果问题规模较小,逻辑控制较为复杂,并行性很小优先使用CPU处理该问题,如果包含较大规模的数据处理,则考虑使用GPU进行处理. CPU上线程是重量级实体,可以开启1~32个线程,且上下文切换较为缓慢, ...