javascript
js hover 触发事件_为什么说JS的DOM操作很耗性能
想問這樣的問題,其實(shí)是自己心中沒有個(gè)譜,一直用 js 計(jì)算性能來衡量 瀏覽器dom 操作性能。js性能和瀏覽器性能其實(shí)是兩碼事。
這個(gè)問題很抽象,它里面涉及挺多個(gè)小的知識(shí)點(diǎn)。
重申一點(diǎn),js 操作 Dom 很耗性能,其實(shí)是在說很耗瀏覽器性能,具體和 js計(jì)算 性能沒多大的關(guān)系;
文章大致行文思路如下:
- URL從輸入到頁面展示的過程
- 渲染HTML的過程
- 為什么很“慢”
- 重排
- 重繪
- 優(yōu)化方案
URL從輸入到頁面展示的過程
這個(gè)是一個(gè)很常見的面試問題。
我這邊只是講解一個(gè)粗略的過程。相當(dāng)于是了解,知道渲染一個(gè)頁面的工作流程,加深大家對(duì)瀏覽器性能的概念。
1、用戶輸入 Url 后,瀏覽器會(huì)根據(jù) url 在本地查找緩存,若是有緩存,直接跳到第5步,若沒有緩存則解析出主機(jī)名。
2、瀏覽器根據(jù)主機(jī)名查找出 ip。
先查找本地 DNS 緩存列表,如果有,則進(jìn)入第4步;若沒有,則想瀏覽器默認(rèn)的 DNS 域名服務(wù)器發(fā)起請(qǐng)求,獲取倒 ip,并緩存在本地 DNS。
3、解析Url獲取倒端口號(hào)。
4、拿到 ip+端口號(hào),則開始建立起一條鏈接目標(biāo)服務(wù)氣的 TCP 鏈接,也就是“三次握手”。
5、瀏覽器向服務(wù)器發(fā)送一條 HTTP 請(qǐng)求報(bào)文
6、服務(wù)器向?yàn)g覽器返回一條 HTTP 響應(yīng)報(bào)文。
7、關(guān)閉連接 瀏覽器解析文檔。
8、如果文檔中有資源則重復(fù)5、6、7、8動(dòng)作,直至資源全部加載完畢。
以上步驟簡(jiǎn)述了瀏覽器從輸入url到最后頁面呈現(xiàn)的大致過程。
在以前,網(wǎng)絡(luò)帶寬還比較小的時(shí)候,前端這方面是要盡量減小首次進(jìn)入頁面的 http請(qǐng)求次數(shù),以提升網(wǎng)頁的打開速度,同時(shí)也減小服務(wù)器的壓力。
在那個(gè)時(shí)代,會(huì)嚴(yán)格要求前端開發(fā)工程師做小圖片的整合,減少頁面img的請(qǐng)求次數(shù)。
針對(duì)這一點(diǎn),建議當(dāng)代的前端設(shè)計(jì)師為了用戶體驗(yàn),要盡量注意以下幾點(diǎn):
- 盡量減小首次進(jìn)入頁面的 http請(qǐng)求次數(shù),特別是在一些并發(fā)量大的業(yè)務(wù)場(chǎng)景。
- 一些活動(dòng)頁面,大多數(shù)展示已經(jīng)用圖片替代,請(qǐng)盡量減小圖片的大小;
- 盡量告知后端同學(xué),對(duì)于返回的數(shù)據(jù),支持 gzip 編碼。這樣js、css的請(qǐng)求數(shù)據(jù)可以大大減小。
渲染 HTML 的過程
當(dāng)瀏覽器下載完所有頁面 HTML 標(biāo)記,JavaScript,CSS,圖片之后,它解析文件并創(chuàng)建兩個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu):一個(gè)DOM Tree樹表示頁面結(jié)構(gòu),一個(gè)是 CSSOM Tree表示DOM節(jié)點(diǎn)如何顯示。
把DOM Tree 和 CSSOM Tree結(jié)合在一起,就成為 Render Tree(渲染樹)。
瀏覽器根據(jù)渲染樹計(jì)算每一個(gè)節(jié)點(diǎn)的幾何信息。這個(gè)就叫做重排(Relayout,更專業(yè)的叫法應(yīng)該是回流(Reflow)。
根據(jù)計(jì)算好的幾何信息,繪制頁面。這個(gè)就叫做重繪(Repainting)。
重繪是一個(gè)非常昂貴的操作。瀏覽器完成一個(gè)dom操作,大多時(shí)間都是花費(fèi)在重繪上面的。
什么叫做重排、重繪?在文章后面有介紹。
為什么很“慢”
通過學(xué)習(xí),我總結(jié)出來,有兩個(gè)方面。
1)瀏覽器響應(yīng) DOM操作 需要一定的成本。程序跑起來都是要花時(shí)間的嘛,對(duì)我們開發(fā)者來說,在乎的是這個(gè)時(shí)間的長(zhǎng)短,更直觀的說法就是卡頓是否肉眼可見。
2)第二點(diǎn)的說法更關(guān)乎技術(shù)。
- Dom操作是由 javaScript 實(shí)現(xiàn)的。
- 瀏覽器對(duì)于DOM操作的響應(yīng),是同步的。
基于這兩點(diǎn),大家想想這種業(yè)務(wù)場(chǎng)景:
// 通過循環(huán)給li元素設(shè)置寬度 var lis = doucument.element.getTagName('li'); for(var i=1;i<10;1++){lis [i].style.width = i +'px' }在這個(gè)代碼中,可以知道,一個(gè) li 的操作,是會(huì)引起瀏覽器的重排重繪的。
DOM是由 js 實(shí)現(xiàn)的,但 js 又是單線程。在這個(gè)代碼中,每一個(gè)li的操作改變,都被存儲(chǔ)在js內(nèi)存當(dāng)中。
也就是說,只有在等 js 代碼跑完了之后,瀏覽器才會(huì)開始響應(yīng)這段代碼所帶來的 js 操作。這些操作扎堆在一起等來瀏覽器來響應(yīng)。瀏覽器的響應(yīng)又是同步的,所以它只能一次一次去執(zhí)行重排計(jì)算,渲染,再計(jì)算,再渲染。。。
這樣,效率其實(shí)很低。重排,重新渲染的計(jì)算量完全取決于 DOM操作 的影響范圍。可能這時(shí),你會(huì)想,瀏覽器就不能智能一點(diǎn)嗎?幾次操作一次計(jì)算,一次渲染不就好了?
嗯。。。也許瀏覽器有它自己的考慮。
重排(Relayout/Reflow)
這一部分,只是想讓更詳細(xì)的了解一下重排的意思。
想要了解重排,要先知道:瀏覽器渲染頁面默認(rèn)采用的是流式布局模型;
所謂重排,實(shí)際上是根據(jù)渲染樹中每個(gè)渲染對(duì)象的信息,計(jì)算出各自渲染對(duì)象的幾何信息(DOM對(duì)象的位置和尺寸大小),并將其安置在界面中的正確位置。
從這個(gè)意思來看,某一個(gè)DOM節(jié)點(diǎn)信息更改了,就需要對(duì)DOM結(jié)構(gòu)進(jìn)行重新計(jì)算,重新布局界面,只是這個(gè)結(jié)構(gòu)更改程度會(huì)決定周邊DOM更改范圍,即全局范圍和局部范圍。
全局范圍就是從根節(jié)點(diǎn) html 開始對(duì)整個(gè)渲染樹進(jìn)行重新布局,例如當(dāng)我們改變了窗口尺寸或方向或者是修改了根元素的尺寸或者字體大小等;而局部布局可以是對(duì)渲染樹的某部分或某一個(gè)渲染對(duì)象進(jìn)行重新布局。
重排一定會(huì)引起重繪。
在此,總結(jié)會(huì)引起重排的操作有:
重繪
相比重排,重繪就簡(jiǎn)單多了,所謂重繪,就是當(dāng)頁面中元素樣式的改變并不影響它在文檔流中的位置時(shí),例如更改了字體顏色,瀏覽器會(huì)將新樣式賦予給元素并重新繪制的過程稱。
常見引起重繪的屬性優(yōu)化方案
DOM操作的背后,隱藏這不止止是文中所描述的這些代價(jià)。為了給用戶更好的瀏覽體驗(yàn),可以有以下優(yōu)化的方案:
- 減少DOM操作
如果在一個(gè)局部方法中需要多次訪問同一個(gè)dom,則先暫存它的引用 - 采用更高效的API或者更高效的寫法
1)用querySelectorAll()替代getElementByXX()。
2)開啟動(dòng)畫的GPU加速,把渲染計(jì)算交給GPU
3)用事件委托來減少事件處理器的數(shù)量。
4)使用react、vue等頁面框架來編寫View頁面。react采用虛擬dom,盡可能的講多次重排濃縮成一次。 - 減少重排
- CSS及動(dòng)畫處理
1)用更高效的css3效果,通過類名控制動(dòng)畫,盡量避免直接操作DOM屬性;
2)在動(dòng)畫的元素多嵌套一層div,盡量用絕對(duì)定位或者固定定位使其脫離文檔流,再進(jìn)行動(dòng)畫處理;
3)盡量在滾動(dòng)的時(shí)候,停止動(dòng)畫;
4)動(dòng)畫實(shí)現(xiàn)的速度選擇。以1px移動(dòng)最為平滑,但是reflow就會(huì)果與頻繁,建議以3px移動(dòng)則會(huì)好很多。
總結(jié)
文中是自己通過學(xué)習(xí),也有借鑒別人的知識(shí)點(diǎn),希望能幫助你。
知識(shí)分享,若有錯(cuò)誤的地方,請(qǐng)留言!
自我學(xué)習(xí),自我勤勉,在未來感謝曾經(jīng)努力的自己!
總結(jié)
以上是生活随笔為你收集整理的js hover 触发事件_为什么说JS的DOM操作很耗性能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java集合中中文排序_利用Collat
- 下一篇: hibernate实战第二版 蒲成带目录