日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

简述浏览器渲染原理

發布時間:2024/1/1 HTML 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简述浏览器渲染原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

瀏覽器渲染原理

瀏覽器渲染過程

大致過程如下:
1 瀏覽器獲取 HTML 文件構建成文檔對象模型樹 DOM(Document Object Model)Tree

DOM 樹的構建是一個深度優先遍歷的過程,當前節點的子節點全部構建才會構建下一個同級節點。DOM 的根節點為 document 對象。DOM 樹的生成過程會被CSS和JS加載執行阻塞。解析過程的實際結束會觸發 DOMContentLoaded 事件

2 當解析到樣式定義,不管是樣式文件還是嵌入的 CSS 都會被解析成層疊樣式表模型 CSSOM(CSS Object Model)
3 根據文檔模型 DOM 和樣式模型CSSOM生成渲染樹 Render tree,渲染樹中包含DOM中除了不可見(display: none 或 )的所有元素。渲染樹即使DOM的直觀展示,包含了 DOM 的相應對象和計算后的樣式。
4 渲染樹的每個元素包含的內容都是計算過的,它被稱之為布局 layout,瀏覽器使用一種流式處理的方法,只需要一次 pass繪制操作就可以布局所有的元素(tables需要多次pass 繪制,pass 表示像素處理和頂點處理)。
5 最后布局完成,渲染樹將轉化為屏幕上的實際內容,這一步被稱為繪制 painting.

JS腳本和CSS文件對渲染過程的影響

CSS 對頁面渲染影響

CSS 可以理解為渲染阻塞資源,當遇到樣式定義時,瀏覽器將不會繼續渲染已經處理的內容, JS 的執行也會暫停,直到處理 CSSOM 構建完畢。但 CSS 加載不會阻塞DOM樹的解析

如果 CSS 文件定義在 head 標簽中,則 CSSOM 會先于 DOM 樹構建,構建完 CSSOM 后,瀏覽器就可以邊構建 DOM,邊完成渲染。

反之如果 CSS 文件定義在所有標簽之后,瀏覽器就會先構建 DOM 樹,構建完 DOM 樹才開始構建 CSSOM 然后會重新渲染頁面,導致資源浪費和不好的交互體驗。可能會出現樣式混亂、白屏等情況。

所以為了優化首屏的效果,需要將盡量精簡的CSS并放在 head 標簽中,不重要的 CSS 也可以選擇放在所有標簽后面,或者使用媒體查詢解除 CSS 對渲染的阻塞。

沒有 js 的理想情況下,html 與 css 會并行解析,分別生成 DOM 與 CSSOM,然后合并成 Render Tree,進入 Rendering Pipeline;但如果有 js,css 加載會阻塞后面 js 語句的執行,而(同步)js 腳本執行會阻塞其后的 DOM 解析(所以通常會把 css 放在頭部, js 放在 body 尾)

JS對頁面渲染影響

JS 可以理解為解析器阻塞,當解析器遇到 script 標簽時,HTML 解析器會被阻塞,DOM 的解析過程會被暫停,直到腳本執行完成。JS 中可以讀取和修改 DOM 屬性和 CSSOM 屬性。

script 標簽有兩個特殊屬性:defer和async
這兩個屬性可以改變阻塞情況,這兩個屬性都會異步下載腳本文件,但是執行時機不同。
這里討論的 script 標簽只有在使用 src 屬性引入外部腳本的情況下。

  • defer
    開啟新的線程下載腳本文件,并且腳本文件會在文檔解析完成后執行。執行完 defer 定義的腳本文件后會觸發 DOMContentLoaded 事件

如果有多個聲明了 defer 的腳本,則會按順序下載和執行

  • async
    開啟新線程下載文件,下載完畢后會立即執行,并阻塞 HTML 解析。

如果有多個聲明 async 的腳本,其下載和執行都是異步的,不能確保彼此的先后順序

async 會在 load 事件之前執行,但并不能確保與 DOMContentLoaded 的執行先后順序

綜上所述,defer 屬性和 async 屬性都能防止腳本下載阻塞頁面渲染。如果腳本之間沒有依賴關系,可以使用 async 屬性,如果腳本之間有依賴關系,應使用 defer 屬性。如果同時使用 async 和 defer 屬性,后者不起作用,瀏覽器行為由 async 屬性決定。如果不想使用這兩個屬性,也可將

回流和重繪

重繪 Repaint

當各種盒子的大小位置都已確定,而是改變某個元素的背景色、文字顏色、邊框顏色等等不影響它周圍或內部布局的屬性時,屏幕的一部分要重畫,但是元素的幾何尺寸沒有變,此時瀏覽器會執行一次重繪。

回流 Reflow

當改變影響文檔內容或結構的操作,就會觸發回流 Reflow,在頁面第一次加載的時候,會觸發一次回流。

回流的操作成本要比重繪要高的多,DOM 樹上的每個節點都有回流 Reflow 的方法,當一個節點回流時,可能會導致子節點、父節點或者兄弟節點都進行回流操作,可能會造成卡頓或者在移動端產生耗電問題。

完成回流過程后,瀏覽器會重新繪制受影響的部分到屏幕上,回流一定會觸發重繪。

會觸發回流的操作:

  • 更改 DOM 的操作,增刪改DOM,位置發生變化
  • CSS 屬性更改
  • 修改元素的 classname
  • 瀏覽器窗口變化
  • 修改默認字體
  • display:none,而 visibility:hidden 只會觸發 repaint,因為沒有發現位置變化

note:有些情況下,比如修改了元素的樣式,瀏覽器并不會立刻 reflow 或 repaint 一次,而是會把這樣的操作積攢一批,然后做一次 reflow,這又叫異步 reflow 或增量異步 reflow。

那么如何減小回流帶來的性能損耗:

  • 減少對 DOM 的多次修改,或使用修改 classname 實現樣式的修改,減少回流次數
  • 如果對 DOM 操作過多可以離線修改 DOM,修改完再添加到頁面中
  • 避免使用 table 布局,因為很小的改動都會導致整個 table 重新布局。

瀏覽器如何解析 CSS選擇器

CSS選擇器的解析是從右到左解析,先找到右節點,對于每一個節點向上查找父節點,直到找到根元素或符合匹配規則的元素,則結束該分支的遍歷。

試想如果從左到右解析的話,發現不符合規則需要回溯造成很大的資源浪費,在性能方面要比從左到右解析要慢很多。

優化渲染性能

  • 優化 JS 執行效率

  • 使用 requestAnimationFrame 替換 setTimeout和setInterval 實現動畫。
  • 長耗時的不影響渲染的計算放到js worker中執行,避免影響頁面解析渲染
  • 降低計算復雜度,降低CSS選擇器的復雜度,使用明確簡單的CSS選擇器能節省計算過程,例如:

    .box:nth-last-child(-n+1) .title {}// 改善后.final-box-title {}
  • 避免大規模復雜布局

布局就是計算DOM元素的大小和位置的過程,如果你的頁面中包含很多元素,那么計算這些元素的位置將耗費很長時間。布局的主要消耗在于:需要布局的DOM元素的數量和布局過程的復雜程度

具體如下:

  • 盡量避免觸發布局:
    當你修改了元素的屬性之后,瀏覽器將會檢查為了使這個修改生效是否需要重新計算布局以及更新渲染樹,對于DOM元素的幾何屬性修改,比如width/height/left/top等,都需要重新計算布局。對于不能避免的布局,可以使用Chrome DevTools工具的Timeline查看布局的耗時,以及受影響的DOM元素數量。

  • 使用flex布局比定位和浮動布局性能更優

  • 避免強制同步布局
    根據渲染流程,JS腳本是在layout之前執行,但是我們可以強制瀏覽器在執行JS腳本之前先執行布局過程,這就是所謂的強制同步布局。

    requestAnimationFrame(logBoxHeight);// 先寫后讀,觸發強制布局function logBoxHeight() {// 更新box樣式box.classList.add('super-big');// 為了返回box的offersetHeight值// 瀏覽器必須先應用屬性修改,接著執行布局過程console.log(box.offsetHeight);}// 先讀后寫,避免強制布局function logBoxHeight() {// 獲取box.offsetHeightconsole.log(box.offsetHeight);// 更新box樣式box.classList.add('super-big');}

    在JS腳本運行的時候,它能獲取到的元素樣式屬性值都是上一幀畫面的,都是舊的值。因此,如果你在當前幀獲取屬性之前又對元素節點有改動,那就會導致瀏覽器必須先應用屬性修改,結果執行布局過程,最后再執行JS邏輯。

  • 避免連續的強制同步布局
    如果連續快速的多次觸發強制同步布局,那么結果更糟糕。比如下面的例子,獲取box的屬性,設置到paragraphs上,由于每次設置paragraphs都會觸發樣式計算和布局過程,而下一次獲取box的屬性必須等到上一步設置結束之后才能觸發。

    function resizeWidth() {// 會讓瀏覽器陷入'讀寫讀寫'循環for (var i = 0; i < paragraphs.length; i++) {paragraphs[i].style.width = box.offsetWidth + 'px';}}// 改善后方案var width = box.offsetWidth;function resizeWidth() {for (var i = 0; i < paragraphs.length; i++) {paragraphs[i].style.width = width + 'px';}}
    • 簡化繪制復雜度、減少繪制區域

      Paint就是填充像素的過程,通常這個過程是整個渲染流程中耗時最長的一環,因此也是最需要避免發生的一環。如果Layout被觸發,那么接下來元素的Paint一定會被觸發。當然純粹改變元素的非幾何屬性,也可能會觸發Paint,比如背景、文字顏色、陰影效果等。

    • 提升移動或漸變元素的繪制層
      繪制并非總是在內存中的單層畫面里完成的,實際上,瀏覽器在必要時會將一幀畫面繪制成多層畫面,然后將這若干層畫面合并成一張圖片顯示到屏幕上。這種繪制方式的好處是,使用transform來實現移動效果的元素將會被正常繪制,同時不會觸發其他元素的繪制。

    • 減少繪制區域,簡化繪制的復雜度
      瀏覽器會把相鄰區域的渲染任務合并在一起進行,所以需要對動畫效果進行精密設計,以保證各自的繪制區域不會有太多重疊。另外可以實現同樣效果的不同方式,應該采用性能更好的那種。

    • 通過Chrome DevTools來分析繪制復雜度和時間消耗,盡可能降低這些指標
      打開DevTools,在彈出的面板中,選中 MoreTools>Rendering選項卡下的Paint flashing,這樣每當頁面發生繪制的時候,屏幕就會閃現綠色的方框。通過該工具可以檢查Paint發生的區域和時機是不是可以被優化。通過Chrome DevTools中的 Timeline>Paint選項可以查看更細節的Paint信息

    • 函數防抖節流
      當系統存在一些高頻觸發的事件函數,例如窗口resize事件、滾動事件和用戶輸入事件,通常會導致連續觸發,增加瀏覽器負擔,導致卡頓影響用戶體驗。此時可以使用函數的防抖和節流減少調用頻率,同時不影響實際效果。

    • 函數防抖
      將多次操作合并成一次操作,使用定時器,在規定的延遲期間多次觸發的事件,都會重置定時器,只有超過延遲時間的時間才會被觸發:

      function debounce(fn, wait) {var timeout = null;return function() {if(timeout !== null) clearTimeout(timeout);timeout = setTimeout(fn, wait);}}// 處理函數function handle() {console.log('action'); }// 事件window.addEventListener('scroll', debounce(handle, 1000));
    • 函數節流
      使函數在一定時間內只會觸發一次。

      var throttle = function(func, delay) {var timer = null;var startTime = Date.now();return function() {var curTime = Date.now();var remaining = delay - (curTime - startTime);var context = this;var args = arguments;clearTimeout(timer);if (remaining <= 0) {func.apply(context, args);startTime = Date.now();} else {timer = setTimeout(func, remaining);}}}function handle() {console.log('action');}window.addEventListener('scroll', throttle(handle, 1000));

    總結

    以上是生活随笔為你收集整理的简述浏览器渲染原理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。