這篇文章將為大家詳細(xì)講解有關(guān)JavaScript內(nèi)存與性能問題的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站設(shè)計、做網(wǎng)站與策劃設(shè)計,山海關(guān)網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:山海關(guān)等地區(qū)。山海關(guān)做網(wǎng)站價格咨詢:18980820575
因為事件處理程序在現(xiàn)代web應(yīng)用中可以實現(xiàn)交互,所以很多開發(fā)者都會錯誤地在頁面中大量使用它們,在JavaScript中,頁面中事件處理程序的數(shù)量與頁面整體性能直接相關(guān)。原因有很多,比如①每個函數(shù)都是對象,都要占用內(nèi)存空間,對象越多,性能越差;②為指定事件處理程序所需訪問DOM的次數(shù)會先造成整個頁面交互的延遲。
for(let value of values){ ul.innerHTML += '
這段代碼效率低,因為每次迭代都要設(shè)置一次innerHTML,不僅如此,每次循環(huán)都要先讀取innerHTML,也就是說一次循環(huán)要訪問兩次innerHTML。
let itemsHtml = "";for(let value of values){ itemsHtml += '
這樣修改之后,效率就高多了,只會對innerHTML進(jìn)行一次賦值,下面代碼也可以搞定:ul.innerHTML = values.map(value => '
過多事件處理程序的解決方案是使用事件委托。事件委托利用事件冒泡,可以只使用一個事件處理程序來管理一種類型的事件。例如,click事件冒泡到document。這意味著可以為整個頁面指定一個onclick事件處理程序,而不是為每個可點(diǎn)擊元素分別指定事件處理程序。
這里包含三個列表項,在被點(diǎn)擊時應(yīng)該執(zhí)行某個操作,通常的方式是指定三個事件處理程序:
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("我是美杜莎!");})
相同代碼太多,代碼過于丑陋了。
使用事件委托,只要給多有元素的共同的祖先節(jié)點(diǎn)添加一個事件處理程序,就可以解決丑陋!
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事件),通過它處理頁面中所有某種類型的事件。這意味著只要頁面渲染出可點(diǎn)擊的元素,就可以無延遲的起作用。
節(jié)省花在設(shè)置頁面事件程序上的事件。
減少整個頁面所需的內(nèi)存,提升整體性能。
把事件處理程序指定給元素后,在瀏覽器代碼和負(fù)責(zé)頁面交互的JavaScript代碼之間就建立了聯(lián)系。這種聯(lián)系簡歷越多,頁面性能就越差。除了通過事件委托來限制這種連接之外,還應(yīng)該及時刪除不用的事件處理程序。很多web應(yīng)用性能不佳都是由于無用的事件處理程序長駐內(nèi)存導(dǎo)致的。
導(dǎo)致這個問題的原因有兩個:
比如通過的DOM方法removeChild()或replaceChild()刪除節(jié)點(diǎn)。最常見的還是使用innerHTML整體替換頁面的某一部分。這時候,被innerHTML刪除的元素上如果有事件處理程序,也不會被垃圾收集程序正常清理。
所以,如果在得知某個元素會被刪除之前,應(yīng)手動刪除它的事件處理程序,比如btn.onclick = null;//刪除事件處理程序
,事件委托也有助于解決這個問題,如果得知某個元素要被innerHTML替代的時候,就不要給該元素添加事件處理程序了,將其添加到更高層級的節(jié)點(diǎn)上即可。
如果在頁面卸載后事件處理程序沒有被清理,則它們?nèi)匀粫埩粼趦?nèi)存中。之后,瀏覽器每次加載和卸載頁面(比如通過前進(jìn)、后退或刷新),內(nèi)存中殘留對象的數(shù)量都會增加,這是因為事件處理程序不會被回收。
一般來說,最好在onunload事件處理程序中趁頁面尚未卸載先刪除所有事件處理程序。這時候也能體現(xiàn)出事件委托的優(yōu)勢,因為事件處理程序少,所以容易記住刪除哪些。
let ps = document.getElementsByTagName("p");for(let i = 0;i表達(dá)式
let ps = document.getElementsByTagName("p");for(let i = 0,len=ps.length;i表達(dá)式①中第一行取得了包含文檔中所有
元素的HTMLCollection。因為這個集合是實時的,所以任何時候只要向頁面中添加一個新的
元素,再查詢這個集合就會多一項。因為瀏覽器不希望保存每次創(chuàng)建的集合,所以就會在每次訪問時更新集合。每次循環(huán)都會求值
i < ps.length
,這意味著要獲取所有元素的查詢。因為循環(huán)體中創(chuàng)建并向文檔中添加一個新的
元素,所以每次循環(huán)ps.length的值也會遞增。因為兩個值都會遞增,所以i永遠(yuǎn)不會等于
ps.length
,因此表達(dá)式①會造成死循環(huán)。
而表達(dá)式②中,又初始化了一個保存集合長度的變量len,因為len保存著循環(huán)開始集合的長度,而這個值不會隨集合增大動態(tài)增長(for循環(huán)中初始化變量處只會初始化一次
),所以就可以避免表達(dá)式①中出現(xiàn)的無窮循環(huán)問題。
如果不想初始化一個變量,也可以使用反向迭代:表達(dá)式
let ps = document.getElementsByTagName("p");for(let i = ps.length-1;i>=0;--i){ let p = document.createElement("p"); document.body.appendChild(p);}七、JavaScript思維導(dǎo)圖
關(guān)于“JavaScript內(nèi)存與性能問題的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
分享名稱:JavaScript內(nèi)存與性能問題的示例分析
網(wǎng)頁地址:http://weahome.cn/article/pgjdss.html