本篇文章為大家帶來了關於javascript的相關知識,其中主要介紹了JavaScript的記憶體與效能問題,包括如何解決類似按鈕過多的問題、刪除事件處理程序等等等,希望對大家有幫助。
相關推薦:javascript教學
因為事件處理程序在現代web應用程式中可以實現交互,所以很多開發者都會錯誤地在頁面中大量使用它們,在JavaScript中,頁面中事件處理程序的數量與頁面整體性能直接相關。原因有很多,例如①每個函數都是對象,都要佔用記憶體空間,物件越多,效能越差;②為指定事件處理程序所需存取DOM的次數會先造成整個頁面互動的延遲。
for(let value of values){ ul.innerHTML += '
這段程式碼效率低,因為每次迭代都要設定一次innerHTML,不只如此,每次迴圈都要先讀取innerHTML,也就是說一次循環要訪問兩次innerHTML。
let itemsHtml = "";for(let value of values){ itemsHtml += '
這樣修改之後,效率就高多了,只會對innerHTML進行一次賦值,下面程式碼也可以搞定:
ul.innerHTML = values.map(value => '<li>${value}</li>').join(' ');
過多事件處理程序的解決方案是使用事件委託。事件委託利用事件冒泡,可以只使用一個事件處理程序來管理一種類型的事件。例如,click事件冒泡到document。這意味著可以為整個頁面指定一個onclick事件處理程序,而不是為每個可點擊元素分別指定事件處理程序。
這裡包含三個清單項,在被點擊時應該執行某個操作,通常的方式是指定三個事件處理程序:
let item1 = document.getElementById("girl1");let item2 = document.getElementById("girl2");let item3 = document.getElementById("girl3");item1.addEventListener("click",(event) => { console.log("我是比比东!");})item2.addEventListener("click",(event) => { console.log("我是云韵!");})item3.addEventListener("click",(event) => { console.log("我是美杜莎!");})
相同程式碼太多,程式碼過於醜陋了。
使用事件委託,只要為多有元素的共同的祖先節點新增一個事件處理程序,就可以解決醜陋!
let list = document.getElementById("myGirls");list.addEventListener("click",(event) => { let target = event.target; switch(target.id){ case "girl1": console.log("我是比比东!"); break; case "girl2": console.log("我是云韵!"); break; case "girl3": console.log("我是美杜莎!"); break; }})
document物件隨時可用,任何時候都可以為它新增一個事件處理程序(不用等待DOMContentLoaded或load事件),透過它處理頁面中所有某種類型的事件。這意味著只要頁面渲染出可點擊的元素,就可以無延遲的運作。
節省花在設定頁面事件程式上的事件。
減少整個頁面所需的內存,提升整體效能。
把事件處理程序指定給元素後,在瀏覽器程式碼和負責頁面互動的JavaScript程式碼之間就建立了聯繫。這種聯絡履歷越多,頁面效能就越差。除了透過事件委託來限制這種連結之外,還應該及時刪除不需要的事件處理程序。許多web應用程式效能不佳都是因為無用的事件處理程序長駐記憶體所導致的。
導致這個問題的原因有兩個:
例如透過的DOM方法removeChild()或replaceChild ()刪除節點。最常見的還是使用innerHTML整體替換頁面的某一部分。這時候,被innerHTML刪除的元素上如果有事件處理程序,也不會被垃圾收集程序正常清理。
所以,如果在得知某個元素會被刪除之前,應手動刪除它的事件處理程序,例如btn.onclick = null;//刪除事件處理程序
,事件委託也有幫助於解決這個問題,如果得知某個元素要被innerHTML取代的時候,就不要給該元素添加事件處理程序了,將其添加到更高層級的節點上即可。
#如果在頁面卸載後事件處理程序沒有被清理,則它們仍然會殘留在內存中。之後,瀏覽器每次載入和卸載頁面(例如透過前進、後退或刷新),記憶體中殘留物件的數量都會增加,這是因為事件處理程序不會被回收。
一般來說,最好在onunload事件處理程序中趁頁面尚未卸載先刪除所有事件處理程序。這時候也能反映出事件委託的優勢,因為事件處理程序少,所以容易記住要刪除哪些。
let ps = document.getElementsByTagName("p");for(let i = 0;i<ps.length let document.body.appendchild><h3><strong>表达式</strong></h3><pre class="brush:php;toolbar:false">let ps = document.getElementsByTagName("p");for(let i = 0,len=ps.length;i<len let document.body.appendchild><p>表达式①中第一行取得了包含文档中所有<code><p></p></code>元素的HTMLCollection。因为这个集合是实时的,所以任何时候只要向页面中添加一个新的<code><p></p></code>元素,再查询这个集合就会多一项。因为浏览器不希望保存每次创建的集合,所以就会在每次访问时更新集合。每次循环都会求值<code>i ,这意味着要获取所有<code><p></p></code>元素的查询。因为循环体中创建并向文档中添加一个新的<code><p></p></code>元素,所以每次循环ps.length的值也会递增。因为两个值都会递增,所以i永远不会等于<code>ps.length</code>,因此表达式①会造成死循环。<br> 而表达式②中,又初始化了一个保存集合长度的变量len,因为len保存着循环开始集合的长度,而这个值不会随集合增大动态增长(<code>for循环中初始化变量处只会初始化一次</code>),所以就可以避免表达式①中出现的无穷循环问题。<br> 如果不想初始化一个变量,也可以使用反向迭代:</code></p> <h3><strong>表达式</strong></h3> <pre class="brush:php;toolbar:false">let ps = document.getElementsByTagName("p");for(let i = ps.length-1;i>=0;--i){ let p = document.createElement("p"); document.body.appendChild(p);}
相关推荐:javascript教程
以上是深入了解JavaScript的記憶體與效能問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!