溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript內(nèi)存與性能問題的示例分析

發(fā)布時(shí)間:2022-03-31 12:20:23 來(lái)源:億速云 閱讀:132 作者:小新 欄目:web開發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)JavaScript內(nèi)存與性能問題的示例分析,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

一、何為JavaScript內(nèi)存與性能

因?yàn)槭录幚沓绦蛟诂F(xiàn)代web應(yīng)用中可以實(shí)現(xiàn)交互,所以很多開發(fā)者都會(huì)錯(cuò)誤地在頁(yè)面中大量使用它們,在JavaScript中,頁(yè)面中事件處理程序的數(shù)量與頁(yè)面整體性能直接相關(guān)。原因有很多,比如①每個(gè)函數(shù)都是對(duì)象,都要占用內(nèi)存空間,對(duì)象越多,性能越差;②為指定事件處理程序所需訪問DOM的次數(shù)會(huì)先造成整個(gè)頁(yè)面交互的延遲。

二、談?wù)勱P(guān)于innerHTML的性能問題?

1、使用innerHTML的反面教材

for(let value of values){
	ul.innerHTML += '<li>${value}</li>';}

這段代碼效率低,因?yàn)槊看蔚家O(shè)置一次innerHTML,不僅如此,每次循環(huán)都要先讀取innerHTML,也就是說一次循環(huán)要訪問兩次innerHTML。

2、如何解

let itemsHtml = "";for(let value of values){
	itemsHtml  += '<li>${value}</li>';}ul.innerHTML = itemsHtml;

這樣修改之后,效率就高多了,只會(huì)對(duì)innerHTML進(jìn)行一次賦值,下面代碼也可以搞定:
ul.innerHTML = values.map(value => '<li>${value}</li>').join(' ');

三、如何解決類似按鈕過多問題?

過多事件處理程序的解決方案是使用事件委托。事件委托利用事件冒泡,可以只使用一個(gè)事件處理程序來(lái)管理一種類型的事件。例如,click事件冒泡到document。這意味著可以為整個(gè)頁(yè)面指定一個(gè)onclick事件處理程序,而不是為每個(gè)可點(diǎn)擊元素分別指定事件處理程序。

<ul id="myGirls">
	<li id="girl1">比比東</li>
	<li id="girl2">云韻</li>
	<li id="girl3">美杜莎</li></ul>

這里包含三個(gè)列表項(xiàng),在被點(diǎn)擊時(shí)應(yīng)該執(zhí)行某個(gè)操作,通常的方式是指定三個(gè)事件處理程序:

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)添加一個(gè)事件處理程序,就可以解決丑陋!

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;
	}})

四、事件委托的優(yōu)點(diǎn)有哪些?

  • document對(duì)象隨時(shí)可用,任何時(shí)候都可以為它添加一個(gè)事件處理程序(不用等待DOMContentLoaded或load事件),通過它處理頁(yè)面中所有某種類型的事件。這意味著只要頁(yè)面渲染出可點(diǎn)擊的元素,就可以無(wú)延遲的起作用。

  • 節(jié)省花在設(shè)置頁(yè)面事件程序上的事件。

  • 減少整個(gè)頁(yè)面所需的內(nèi)存,提升整體性能。

五、刪除事件處理程序

把事件處理程序指定給元素后,在瀏覽器代碼和負(fù)責(zé)頁(yè)面交互的JavaScript代碼之間就建立了聯(lián)系。這種聯(lián)系簡(jiǎn)歷越多,頁(yè)面性能就越差。除了通過事件委托來(lái)限制這種連接之外,還應(yīng)該及時(shí)刪除不用的事件處理程序。很多web應(yīng)用性能不佳都是由于無(wú)用的事件處理程序長(zhǎng)駐內(nèi)存導(dǎo)致的。
導(dǎo)致這個(gè)問題的原因有兩個(gè):

1、刪除帶有事件處理程序的元素

比如通過的DOM方法removeChild()或replaceChild()刪除節(jié)點(diǎn)。最常見的還是使用innerHTML整體替換頁(yè)面的某一部分。這時(shí)候,被innerHTML刪除的元素上如果有事件處理程序,也不會(huì)被垃圾收集程序正常清理。
所以,如果在得知某個(gè)元素會(huì)被刪除之前,應(yīng)手動(dòng)刪除它的事件處理程序,比如btn.onclick = null;//刪除事件處理程序,事件委托也有助于解決這個(gè)問題,如果得知某個(gè)元素要被innerHTML替代的時(shí)候,就不要給該元素添加事件處理程序了,將其添加到更高層級(jí)的節(jié)點(diǎn)上即可。

2、頁(yè)面卸載也會(huì)導(dǎo)致內(nèi)存中殘留引用的問題

如果在頁(yè)面卸載后事件處理程序沒有被清理,則它們?nèi)匀粫?huì)殘留在內(nèi)存中。之后,瀏覽器每次加載和卸載頁(yè)面(比如通過前進(jìn)、后退或刷新),內(nèi)存中殘留對(duì)象的數(shù)量都會(huì)增加,這是因?yàn)槭录幚沓绦虿粫?huì)被回收。
一般來(lái)說,最好在onunload事件處理程序中趁頁(yè)面尚未卸載先刪除所有事件處理程序。這時(shí)候也能體現(xiàn)出事件委托的優(yōu)勢(shì),因?yàn)槭录幚沓绦蛏?,所以容易記住刪除哪些。

六、如何解決循環(huán)中動(dòng)態(tài)添加p,造成的死循環(huán)問題?

表達(dá)式

let ps = document.getElementsByTagName("p");for(let i = 0;i<ps.length;++i){
	let p = document.createElement("p");
	document.body.appendChild(p);}

表達(dá)式

let ps = document.getElementsByTagName("p");for(let i = 0,len=ps.length;i<len;++i){
	let p = document.createElement("p");
	document.body.appendChild(p);}

表達(dá)式①中第一行取得了包含文檔中所有<p>元素的HTMLCollection。因?yàn)檫@個(gè)集合是實(shí)時(shí)的,所以任何時(shí)候只要向頁(yè)面中添加一個(gè)新的<p>元素,再查詢這個(gè)集合就會(huì)多一項(xiàng)。因?yàn)闉g覽器不希望保存每次創(chuàng)建的集合,所以就會(huì)在每次訪問時(shí)更新集合。每次循環(huán)都會(huì)求值i < ps.length,這意味著要獲取所有<p>元素的查詢。因?yàn)檠h(huán)體中創(chuàng)建并向文檔中添加一個(gè)新的<p>元素,所以每次循環(huán)ps.length的值也會(huì)遞增。因?yàn)閮蓚€(gè)值都會(huì)遞增,所以i永遠(yuǎn)不會(huì)等于ps.length,因此表達(dá)式①會(huì)造成死循環(huán)。
而表達(dá)式②中,又初始化了一個(gè)保存集合長(zhǎng)度的變量len,因?yàn)閘en保存著循環(huán)開始集合的長(zhǎng)度,而這個(gè)值不會(huì)隨集合增大動(dòng)態(tài)增長(zhǎng)(for循環(huán)中初始化變量處只會(huì)初始化一次),所以就可以避免表達(dá)式①中出現(xiàn)的無(wú)窮循環(huán)問題。
如果不想初始化一個(gè)變量,也可以使用反向迭代:

表達(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)圖

JavaScript內(nèi)存與性能問題的示例分析

關(guān)于“JavaScript內(nèi)存與性能問題的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI