本文目錄一覽:
渲染機制、迴流、重繪
解析 HTML 標籤, 構建 DOM 樹
解析 CSS, 構建 CSSOM 樹
把 DOM 和 CSSOM 組合成渲染樹 (render tree)
在渲染樹的基礎上進行布局, 計算每個節點的幾何結構
把每個節點繪製到屏幕上 (painting)
Reflow:重新計算元素的幾何尺寸、位置 + repaint
Repaint:繪製界面發生變化的部分
(迴流會引起重繪,所以代價更大)
添加、刪除、更新DOM節點(reflow、repaint)
修改元素的magin、padding、border(reflow、repaint)
display: none(reflow、repaint)
visibility: hidden(repaint)
修改顏色、背景色 (repaint)
盡量一次性修改樣式
DOM離線後修改
給動畫使用絕對定位可以減小 reflow ?
javascript – What’s the difference between reflow and repaint? – Stack Overflow
js優化中,離線操作dom中的“離線”怎麼理解? – SegmentFault 思否
瀏覽器中動畫渲染效率原生js高還是css高?
css的執行順序是優先於js的,
css一旦被引入,立即存到瀏覽器內存中,
動畫的話,當然是css高
瀏覽器的渲染過程及涉及到的緩存機制
答:dns解析-》tcp鏈接-》發送HTTP請求-》服務器處理請求並且返回報文-》瀏覽器解析渲染頁面-》鏈接結束
是一個將網址解析成IP 地址的過程。
首先從本地域名服務器中查找,如果找不到就繼續向上根域名服務器查找,直到頂級域名,這個過程中存在dns優化有的環節。當查找資源時, 會先找緩存,(瀏覽器緩存-》系統緩存-》路由器緩存等等),也會根據機器的負載量和距離用戶的位置進行dns負載均衡。
A.客戶端發送syn到服務器要求連接
B.服務端向客戶端發送ack
C.客戶端收到ack並確認後,向服務端發送ack,連連接建立。
tcp連接建立之後,開始通過HTTP協議傳輸資源,根據情況判斷是否使用HTTPS,HTTP包括請求行,請求報頭,請求正文(post,put客戶端向服務器傳輸數據的情況)。keepalive什麼的可以在請求頭裡添加。
(此處涉及強制緩存和協商緩存, 為了先講清楚瀏覽器渲染過程,我把他們放在文章末尾。)
服務端接到請求開始對tcp進行處理,對http進行解析,按照報文格式封裝成HTTP request對象。響應報文碼(1xx:請求已接受,2XX:成功,3xx:重定向,4xx:客戶端錯誤,5xx:服務端錯誤)
邊解析邊渲染,首先解析html,構建dom樹,然後解析css,構建cssom。
我思考過很久HTML和css誰先渲染。我的理解是,不一定,看位置了,如果dom構建的過程中遇到了css的link,那就會先去加載並構建cssom,這個過程不是一次性的。 css和同步的js文件都是阻塞DOM樹渲染的,但不阻塞DOM解析, 直到js加載並且執行完畢。遇到阻塞的css也會延遲js的執行和dom構建。(因為js可能會修改dom或者cssom),css同樣,當cssom構建時,js也會停止被阻塞,等待cssom構建完成。
defer async
1.正常模式
script src=”script.js”/script
遇到這樣的js標籤,瀏覽器會立即加載並執行,不等待後續載入的文檔元素。
2.async模式
script async src=”script.js”/script
有async的js文件會和後續的DOM解析渲染並行執行,當js加載完成,立即執行,這時html解析暫停。因此不會按照標籤引入順序執行。
3.defer模式
script defer src=”script.js”/script
有defer的js文件的加載,也會和文檔的解析構建並行。這一點與async一致。
不同的是,defer的js文件加載完不會立即執行, 會等到所有文檔解析完成後,DOMContentLoaded事件觸發之前完成, 因此會按照引入順序執行。
DOMContentLoaded onload
DOM解析完(阻塞DOM的內容解析完,DOM才真正解析完)會觸發DOMContentLoaded事件。如果在DOMContentLoaded之後引入css樣式表,DOMContentLoaded可能無法獲取樣式表裡的樣式,此時DOM樹已經構建完成,但外部css文件還沒加載完成,這也是 css文件放在頭部的原因 。
onLoad
頁面的所有資源被加載以後觸發onLoad事件,會在DOMContentLoaded之後觸發。
這個過程中有兩個重要的過成是迴流和重繪。計算盒模型的大小位置還有解析顏色字體等 屬性,這些都確定下來的時候開始repain,合成一個rendertree渲染樹,render-tree中必須同時存在dom和cssom,瀏覽器開始布局並渲染到屏幕上。首次加載必然會經歷迴流和重繪的過程。
無論何時總會有一個初始化的頁面布局伴隨着一次繪製。(除非你希望你的頁面是空白的:))之後,每一次改變用於構建渲染樹的信息都會導致以下至少一個的行為:
部分渲染樹(或者整個渲染樹)需要重新分析並且節點尺寸需要重新計算。這被稱為重排。注意這裡至少會有一次重排-初始化頁面布局。
由於節點的幾何屬性發生改變或者由於樣式發生改變,例如改變元素背景色時,屏幕上的部分內容需要更新。這樣的更新被稱為重繪。
重排和重繪代價是高昂的,它們會破壞用戶體驗,並且讓UI展示非常遲緩。
一些重排可能開銷更大。想象一下渲染樹,如果你直接改變body下的一個子節點,可能並不會對其它節點造成影響。但是當你給一個當前頁面頂級的div添加動畫或者改變它的大小,就會推動整個頁面改變-聽起來代價就十分高昂。
瀏覽器一直致力於減少這些消極的影響,瀏覽器會創建一個變化的隊列,瀏覽器可以向隊列添加或變更這些變化,在一個特定的時間或達到一定的數量時,執行一次重排或重繪,通過這種方式,多次重排或重繪會整合起來最終減少重排或重繪的次數,以節省瀏覽器渲染的開銷。
所以 ,同時set和get樣式是非常糟糕的做法
看到的一個答案,有可能是這個原因,但是我不確定。
開發環境會把css都打包到js里,所以要等js加載好了才有樣式,因此會出現這種情況;但是在生產環境下,css會生成css文件,並插入到style /里,因此就不會出現這種情況了。
兩個優化點:css先加載,js後加載
js盡量不要修改dom樹。
以下是我在OneNote的筆記,粘貼過來就會變成圖片沒有找到好的辦法。
強制緩存和協商緩存是http請求這一步的內容。
前端性能優化總結(一)-js、css優化
移動互聯網時代,用戶對於網頁的打開速度要求越來越高。首屏作為直面用戶的第一屏,其重要性不言而喻。優化用戶體驗更是我們前端開發非常需要 focus 的東西之一。
從用戶的角度而言,當打開一個網頁,往往關心的是從輸入完網頁地址後到最後展現完整頁面這個過程需要的時間,這個時間越短,用戶體驗越好。所以作為網頁的開發者,就從輸入url到頁面渲染呈現這個過程中去提升網頁的性能。
所以輸入URL後發生了什麼呢?在瀏覽器中輸入url會經歷域名解析、建立TCP連接、發送http請求、資源解析等步驟。
http緩存優化是網頁性能優化的重要一環,這一部分我會在後續筆記中做一個詳細總結,所以本文暫不多做詳細整理。本文主要從網頁渲染過程、網頁交互以及Vue應用優化三個角度對性能優化做一個小結。
首先談談拿到服務端資源後瀏覽器渲染的流程:
關鍵渲染路徑是瀏覽器將 HTML、CSS、JavaScript 轉換為在屏幕上呈現的像素內容所經歷的一系列步驟。也就是我們剛剛提到的的的瀏覽器渲染流程。
為儘快完成首次渲染,我們需要最大限度減小以下三種可變因素:
首先,DOM 和 CSSOM 通常是並行構建的,所以 CSS 加載不會阻塞 DOM 的解析。
然而,由於 Render Tree 是依賴於 DOM Tree 和 CSSOM Tree 的,
所以他必須等待到 CSSOM Tree 構建完成,也就是 CSS 資源加載完成(或者 CSS 資源加載失敗)後,才能開始渲染。因此,CSS 加載會阻塞 Dom 的渲染。
由此可見,對於 CSSOM 縮小、壓縮以及緩存同樣重要,我們可以從這方面考慮去優化。
當瀏覽器遇到 script 標記時,會阻止解析器繼續操作,直到 CSSOM 構建完畢,JavaScript 才會運行並繼續完成 DOM 構建過程。
當頁面中元素樣式的改變並不影響它在文檔流中的位置時(例如:color、background-color、visibility 等),瀏覽器會將新樣式賦予給元素並重新繪製它,這個過程稱為重繪。
迴流(Reflow)
當 Render Tree 中部分或全部元素的尺寸、結構、或某些屬性發生改變時,瀏覽器重新渲染部分或全部文檔的過程稱為迴流。
有時即使僅僅迴流一個單一的元素,它的父元素以及任何跟隨它的元素也會產生迴流。現代瀏覽器會對頻繁的迴流或重繪操作進行優化:瀏覽器會維護一個隊列,把所有引起迴流和重繪的操作放入隊列中,如果隊列中的任務數量或者時間間隔達到一個閾值的,瀏覽器就會將隊列清空,進行一次批處理,這樣可以把多次迴流和重繪變成一次。
當你訪問以下屬性或方法時,瀏覽器會立刻清空隊列:
因為隊列中可能會有影響到這些屬性或方法返回值的操作,即使你希望獲取的信息與隊列中操作引發的改變無關,瀏覽器也會強行清空隊列,確保你拿到的值是最精確的。
避免頻繁操作樣式,最好一次性重寫 style 屬性,或者將樣式列表定義為 class 並一次性更改 class 屬性。
避免頻繁操作 DOM,創建一個 documentFragment,在它上面應用所有 DOM 操作,最後再把它添加到文檔中。
也可以先為元素設置 display: none,操作結束後再把它顯示出來。因為在 display 屬性為 none 的元素上進行的 DOM 操作不會引發迴流和重繪。
避免頻繁讀取會引發迴流/重繪的屬性,如果確實需要多次使用,就用一個變量緩存起來。
對具有複雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及後續元素頻繁迴流。
圖片懶加載在一些圖片密集型的網站中運用比較多,通過圖片懶加載可以讓一些不可視的圖片不去加載,避免一次性加載過多的圖片導致請求阻塞(瀏覽器一般對同一域名下的並發請求的連接數有限制),這樣就可以提高網站的加載速度,提高用戶體驗。
將頁面中的img標籤src指向一張小圖片或者src為空,然後定義data-src(這個屬性可以自定義命名,我才用data-src)屬性指向真實的圖片。src指向一張默認的圖片,否則當src為空時也會向服務器發送一次請求。可以指向loading的地址。注意,圖片要指定寬高。
當載入頁面時,先把可視區域內的img標籤的data-src屬性值負給src,然後監聽滾動事件,把用戶即將看到的圖片加載。這樣便實現了懶加載。
事件委託其實就是利用JS事件冒泡機制把原本需要綁定在子元素的響應事件(click、keydown……)委託給父元素,讓父元素擔當事件監聽的職務。事件代理的原理是DOM元素的事件冒泡。
優點:
例如有一個列表需要綁定點擊事件,每一個列表項的點擊都需要返回不同的結果。
傳統寫法:
傳統方法會利用for循環遍歷列表為每一個列表元素綁定點擊事件,當列表中元素數量非常龐大時,需要綁定大量的點擊事件,這種方式就會產生性能問題。這種情況下利用事件委託就能很好的解決這個問題。
改用事件委託:
輸入搜索時,可以用防抖debounce等優化方式,減少http請求;
這裡以滾動條事件舉例:防抖函數 onscroll 結束時觸發一次,延遲執行
節流函數:只允許一個函數在N秒內執行一次。滾動條調用接口時,可以用節流throttle等優化方式,減少http請求;
下面還是一個簡單的滾動條事件節流函數:節流函數 onscroll 時,每隔一段時間觸發一次,像水滴一樣
參考鏈接:
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/303095.html