详解Vue如何避免内存泄漏
作者:Mr.怪兽
1.前言
使用Vue开发应用时,需要注意内存泄漏的问题,因为Vue所采用的是SPA设计,用户使用时是不需要刷新浏览器的,所以需要js来清理组件确保垃圾回收避免内存泄漏。
内存泄漏在Vue应用中通常不是来自于其本身,更多的是发生在把其它的库或者组件集成到该应用中时。
2.案例
这个案例展示一个由于在vue组件中使用Choices.js库而没有及时用完清除导致内存泄漏问题。
示例中:加载了一个带有非常多的选择项的选择框,然后用到了以恶搞显示/隐藏按钮,通过一个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 } } })
根据上述示例,在页面中操作点击 显示/隐藏按钮50次左右,则会在浏览器任务管理器中发现内存的使用在增加并且从未被回收。
3.解决内存泄漏问题
在上述示例中,可以使用 hide() 方法在将选择框从DOM中移除之前做一些清理工作,来解决内存泄漏问题。在Vue实例的数据对象中保留一个属性,并会使用ChoicesAPI中的 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 } } })
4.这样做的目的
内存管理和性能测试在快速交付的时候很容易被忽视,所以尽量保持小内存开销会让用户体验感觉更好。
考虑到不同用户是用的设备类型以及使用方式不同,他们使用的是内存有限的电脑设备或者移动设备吗?或者用户会做很多应用内的导航吗?如果是其中之一的话,保持一个良好的内存管理实践会避免糟糕的浏览器卡顿崩溃的场景,也避免了在持续使用中存在潜在的性能恶化问题。
5.实际例子
更常见的实际场景使用 Vue Router 在一个单页面应用中路由导航到不同的组件。
就像 v-if 指令一样,当一个用户在应用中导航时,Vue Router 从虚拟DOM中移除了该元素,并替换为新的元素。Vue 的 beforeDestroy() 钩子函数是一个解决Vue Router 的应用中的这类问题的好地方。
可以将要清理内存的工作放在 beforeDestroy() 中处理:
beforeDestroy: function(){ this.choicesSelect.destroy() }
6.替代方案
另一个场景:如果打算在内存中保留状态和该元素,则可以采用内置的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 () { // 移除任何你不想保留的数据 }
7.总结
Vue 让开发响应式应用程序变得特别容易,但是仍然要警惕内存泄漏问题,这些内存泄露问题会发生在使用Vue之外的其他DOM操作的三方库时,请确保在不使用的情况下及时清理,保证用户的更好体验
到此这篇关于详解Vue如何避免内存泄漏的文章就介绍到这了,更多相关Vue 避免内存泄漏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!