Vue优化:常见会导致内存泄漏问题及优化详解


Posted in Javascript onAugust 04, 2020

如果你在用 Vue 开发应用,那么就要当心内存泄漏的问题。这个问题在单页应用 (SPA) 中尤为重要,因为在 SPA 的设计中,用户使用它时是不需要刷新浏览器的,所以 JavaScript 应用需要自行清理组件来确保垃圾回收以预期的方式生效。因此在vue开发过程中,你需要时刻警惕内存泄漏的问题,这些内存泄漏往往会发生在使用 Vue 之外的其它进行 DOM 操作的三方库时,请确保测试应用的内存泄漏问题并在适当的时机做必要的组件清理。

下面是我开发过程中遇到,并查资料总结的内存泄漏问题,会持续更新中

一、vue自定义指令给元素绑定事件,却没有解绑事件

这个问题见上篇博客,vue自定义指令导致的内存泄漏问题解决

二、v-if指令产生的内存泄露

v-if也是一个容易产生内存泄漏的地方。因为:

1、v-if绑定到false的值,但是实际上dom元素在隐藏的时候没有被真实的释放掉

2、就是非常常见的比如我们通过v-if删除了父级元素,但是并没有移除父级元素里的dom片段。通常产生于使用第三方库的时候,比如下面的示例中,我们加载了一个带有非常多选项的选择框,然后我们用到了一个显示/隐藏按钮,通过一个 v-if 指令从虚拟 DOM 中添加或移除它。这个示例的问题在于这个 v-if 指令会从 DOM 中移除父级元素,但是我们并没有清除由 Choices.js 新添加的 DOM 片段,从而导致了内存泄漏。

<link rel="stylesheet prefetch" href="https://joshuajohnson.co.uk/Choices/assets/styles/css/choices.min.css?version=3.0.3" rel="external nofollow" >
<script src="https://joshuajohnson.co.uk/Choices/assets/scripts/dist/choices.min.js?version=3.0.3"></script>

<div id="app">
 <button v-if="showChoices" @click="hide">Hide</button>
 <button v-if="!showChoices" @click="show" >Show</button>
 <div v-if="showChoices">
 <select id="choices-single-default"></select>
 </div>
</div>
new Vue({
 el: "#app",
 data: function () {
 return {
  showChoices: true
 }
 },
 mounted: function () {
 this.initializeChoices()
 },
 methods: {
 initializeChoices: function () {
  let list = []
  // 我们来为选择框载入很多选项
  // 这样的话它会占用大量的内存
  for (let i = 0; i < 1000; i++) {
  list.push({
   label: "Item " + i,
   value: i
  })
  }
  new Choices("#choices-single-default", {
  searchEnabled: true,
  removeItemButton: true,
  choices: list
  })
 },
 show: function () {
  this.showChoices = true
  this.$nextTick(() => {
  this.initializeChoices()
  })
 },
 hide: function () {
  this.showChoices = false
 }
 }
})

解决实例:在上述的示例中,我们可以用 hide() 方法在将选择框从 DOM 中移除之前做一些清理工作,来解决内存泄露问题。为了做到这一点,我们会在 Vue 实例的数据对象中保留一个属性,并会使用 Choices API 中的 destroy() 方法将其清除。

new Vue({
 el: "#app",
 data: function () {
 return {
  showChoices: true,
  choicesSelect: null
 }
 },
 mounted: function () {
 this.initializeChoices()
 },
 methods: {
 initializeChoices: function () {
  let list = []
  for (let i = 0; i < 1000; i++) {
  list.push({
   label: "Item " + i,
   value: i
  })
  }
  // 在我们的 Vue 实例的数据对象中设置一个 `choicesSelect` 的引用
  this.choicesSelect = new Choices("#choices-single-default", {
  searchEnabled: true,
  removeItemButton: true,
  choices: list
  })
 },
 show: function () {
  this.showChoices = true
  this.$nextTick(() => {
  this.initializeChoices()
  })
 },
 hide: function () {
  // 现在我们可以让 Choices 使用这个引用
  // 在从 DOM 中移除这些元素之前进行清理工作
  this.choicesSelect.destroy()
  this.showChoices = false
 }
 }
})

三、vue-router跳转到别的组件导致的内容泄漏

在上述示例中,我们使用了一个 v-if 指令产生内存泄漏,但是一个更常见的实际的场景是使用 Vue Router 在一个单页应用中路由到不同的组件。

就像这个 v-if 指令一样,当一个用户在你的应用中导航时,Vue Router 从虚拟 DOM 中移除了元素,并替换为了新的元素。但是其子元素dom片段也并没有销毁。

Vue 的 beforeDestroy() 生命周期钩子是一个解决基于 Vue Router 的应用中的这类问题的好方法。我们可以将清理工作放入 beforeDestroy() 钩子,像这样:

beforeDestroy: function () {
 this.choicesSelect.destroy()
}

所以最正确的解决方案就是:首先,v-if置为false前先删除创建的dom片段;其次,路由跳出吃,在beforeDestroy钩子函数里面判断choicesSelect是否销毁,没销毁则销毁。

还有一个替代方案:

我们已经讨论了移除元素时的内存管理,但是如果你打算在内存中保留状态和元素该怎么做呢?这种情况下,你可以使用内建的 keep-alive 组件。

当你用 keep-alive 包裹一个组件后,它的状态就会保留,因此就留在了内存里。

<button @click="show = false">Hide</button>
<keep-alive>
 // <my-component> 即便被删除仍会刻意保留在内存里
 <my-component v-if="show"></my-component>
</keep-alive>

这个技巧可以用来提升用户体验。例如,设想一个用户在一个文本框中输入了评论,之后决定导航离开。如果这个用户之后导航回来,那些评论应该还保留着。

一旦你使用了 keep-alive,那么你就可以访问另外两个生命周期钩子:activated和 deactivated。如果你想要在一个 keep-alive 组件被移除的时候进行清理或改变数据,可以使用 deactivated 钩子。

deactivated: function () {
 // 移除任何你不想保留的数据,或者销毁可能产生内存泄漏的地方
}

以上这篇Vue优化:常见会导致内存泄漏问题及优化详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 动态添加表格行 使用模板、标记
Oct 24 Javascript
jQuery插件slicebox实现3D动画图片轮播切换特效
Apr 12 Javascript
jquery实现右侧栏菜单选择操作
Mar 04 Javascript
JS日程管理插件FullCalendar中文说明文档
Feb 06 Javascript
JS基于onclick事件实现单个按钮的编辑与保存功能示例
Feb 13 Javascript
JavaScript 中 apply 、call 的详解
Mar 21 Javascript
AngularJS封装$http.post()实例详解
May 06 Javascript
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
Jul 12 jQuery
vue 路由页面之间实现用手指进行滑动的方法
Feb 23 Javascript
AngularJS模态框模板ngDialog的使用详解
May 11 Javascript
微信小程序新手教程之启动页的重要性
Mar 03 Javascript
如何使用gpu.js改善JavaScript的性能
Dec 01 Javascript
Jquery cookie插件实现原理代码解析
Aug 04 #jQuery
解决vue自定义指令导致的内存泄漏问题
Aug 04 #Javascript
vue中的v-model原理,与组件自定义v-model详解
Aug 04 #Javascript
详解JS深拷贝与浅拷贝
Aug 04 #Javascript
vue addRoutes路由动态加载操作
Aug 04 #Javascript
vue+element使用动态加载路由方式实现三级菜单页面显示的操作
Aug 04 #Javascript
Vue登录拦截 登录后继续跳转指定页面的操作
Aug 04 #Javascript
You might like
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
利用Memcached在php下实现session机制 替换PHP的原生session支持
2010/08/21 PHP
PHP中遇到BOM、编码导致json_decode函数无法解析问题
2014/07/02 PHP
PHP实现的sqlite数据库连接类
2014/12/12 PHP
php生成酷炫的四个字符验证码
2016/04/22 PHP
php简单创建zip压缩文件的方法
2016/04/30 PHP
Laravel Validator 实现两个或多个字段联合索引唯一
2019/05/08 PHP
javascript对象的property和prototype是这样一种关系
2007/03/24 Javascript
兼容ie、firefox的图片自动缩放的css跟js代码分享
2012/01/21 Javascript
Extjs中RowExpander控件的默认展开问题示例探讨
2014/01/24 Javascript
jQuery实现HTML5 placeholder效果实例
2014/12/09 Javascript
javascript实现当前页导航激活的方法
2015/02/27 Javascript
理解javascript函数式编程中的闭包(closure)
2016/03/08 Javascript
js css实现垂直方向自适应的三角提示菜单
2016/06/26 Javascript
JavaScript数据类型转换的注意事项
2016/07/31 Javascript
解决vue 路由变化页面数据不刷新的问题
2018/03/13 Javascript
深入浅析Vue全局组件与局部组件的区别
2018/06/15 Javascript
解决koa2 ctx.render is not a function报错问题
2018/08/07 Javascript
vue动态路由:路由参数改变,视图不更新问题的解决
2019/11/05 Javascript
jquery插件懒加载的示例
2020/10/24 jQuery
[01:12](回顾)DOTA2国际邀请赛,全世界DOTAer的盛宴
2014/07/01 DOTA
easy_install python包安装管理工具介绍
2013/02/10 Python
python自动发送邮件脚本
2018/06/20 Python
解决python 3 urllib 没有 urlencode 属性的问题
2019/08/22 Python
如何验证python安装成功
2020/07/06 Python
Python3爬虫关于代理池的维护详解
2020/07/30 Python
appium+python自动化配置(adk、jdk、node.js)
2020/11/17 Python
领导班子整改方案
2014/10/25 职场文书
领导欢迎词致辞
2015/01/23 职场文书
民事二审代理词
2015/05/25 职场文书
2016暑期校本培训心得体会
2016/01/08 职场文书
Nginx反向代理及负载均衡如何实现(基于linux)
2021/03/31 Servers
python开发飞机大战游戏
2021/07/15 Python
使用MybatisPlus打印sql语句
2022/04/22 SQL Server
在SQL Server中使用 Try Catch 处理异常的示例详解
2022/07/15 SQL Server
win10系统计算机图标怎么调出来?win10调出计算机图标的方法
2022/08/14 数码科技