Js中常见的内存泄漏场景 (2)

计时器setInterval必须及时清理,否则可能由于其中引用的变量或者函数都被认为是需要的而不会进行回收,如果内部引用的变量存储了大量数据,可能会引起页面占用内存过高,这样就造成意外的内存泄漏。

<template> <div></div> </template> <script> export default { creates: function() { this.refreshInterval = setInterval(() => this.refresh(), 2000); }, beforeDestroy: function() { clearInterval(this.refreshInterval); }, methods: { refresh: function() { // do something }, }, } </script> 脱离DOM的引用

有时保存DOM节点内部数据结构很有用,例如需要快速更新表格的几行内容,把每一行DOM存成字典或者数组很有意义。此时同样的DOM元素存在两个引用:一个在DOM树中,另一个在字典中。将来如果决定删除这些行时,需要把两个引用都清除。此外还要考虑DOM树内部或子节点的引用问题,假如你的JavaScript代码中保存了表格某一个<td>的引用,将来决定删除整个表格的时候,直觉认为GC会回收除了已保存的<td>以外的其它节点,实际情况并非如此,此<td>是表格的子节点,子元素与父元素是引用关系,由于代码保留了<td>的引用,导致整个表格仍待在内存中,所以在保存DOM元素引用的时候,要小心谨慎。

var elements = { button: document.getElementById("button"), image: document.getElementById("image"), text: document.getElementById("text") }; function doStuff() { elements.image.src = "https://www.example.com/1.jpg"; elements.button.click(); console.log(elements.text.innerHTML); // 更多逻辑 } function removeButton() { // 按钮是 body 的后代元素 document.body.removeChild(elements.button); elements.button = null; // 清除对于这个对象的引用 } 闭包

闭包是JavaScript开发的一个关键方面,闭包可以让你从内部函数访问外部函数作用域,简单来说可以认为是可以从一个函数作用域访问另一个函数作用域而非必要在函数作用域中实现作用域链结构。由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,过度使用闭包可能会导致内存占用过多,在不再需要的闭包使用结束后需要手动将其清除。

function debounce(wait, funct, ...args){ // 防抖函数 var timer = null; return () => { clearTimeout(timer); timer = setTimeout(() => funct(...args), wait); } } window.onscroll = debounce(300, (a) => console.log(a), 1); 被遗忘的监听者模式

当实现了监听者模式并在组件内挂载相关的事件处理函数,而在组件销毁时不主动将其清除时,其中引用的变量或者函数都被认为是需要的而不会进行回收,如果内部引用的变量存储了大量数据,可能会引起页面占用内存过高,这样就造成意外的内存泄漏。

<template> <div ></div> </template> <script> export default { created: function() { global.eventBus.on("test", this.doSomething); }, beforeDestroy: function(){ global.eventBus.off("test", this.doSomething); }, methods: { doSomething: function() { // do something }, }, } </script> 被遗忘的事件监听器

当事件监听器在组件内挂载相关的事件处理函数,而在组件销毁时不主动将其清除时,其中引用的变量或者函数都被认为是需要的而不会进行回收,如果内部引用的变量存储了大量数据,可能会引起页面占用内存过高,这样就造成意外的内存泄漏。

<template> <div></div> </template> <script> export default { created: function() { window.addEventListener("resize", this.doSomething); }, beforeDestroy: function(){ window.removeEventListener("resize", this.doSomething); }, methods: { doSomething: function() { // do something }, }, } </script> 被遗忘的Map

当使用Map存储对象时,类似于脱离DOM的引用,如果不将其主动清除引用,其同样会造成内存不自动进行回收,对于键为对象的情况,可以采用WeakMap,WeakMap对象同样用来保存键值对,对于键是弱引用的而且必须为一个对象,而值可以是任意的对象或者原始值,且由于是对于对象的弱引用,其不会干扰Js的垃圾回收。

var elements = new Map(); elements.set("button", document.getElementById("button")); function doStuff() { elements.get("button").click(); // 更多逻辑 } function removeButton() { // 按钮是 body 的后代元素 document.body.removeChild(elements.get("button")); elements.delete("button"); // 清除对于这个对象的引用 } 被遗忘的Set

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspxwx.html