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

歡迎訪問 生活随笔!

生活随笔

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

HTML

关闭浏览器网页触发事件_浅析浏览器渲染和 script 加载

發布時間:2023/12/20 HTML 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关闭浏览器网页触发事件_浅析浏览器渲染和 script 加载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

前端代碼離不開瀏覽器環境,理解 js、css 代碼如何在瀏覽器中工作是非常重要的。

如何優化渲染過程中的回流,重繪?script 腳本在頁面中是怎么個加載順序?了解這些對前端性能優化起著非常大的作用。

借著這篇文章,讓自己對這塊知識的理解更深一步。

渲染

渲染樹(Render Tree)

瀏覽器通過解析 HTML 和 CSS 后,形成對應的 DOM 樹和 CSSOM 樹。

從根節點開始解析 DOM 樹節點并匹配對應的 CSSOM 樣式規則,選擇可見的的節點,最終結合成一顆渲染樹

從上圖能看到渲染樹的特點:

  • 渲染樹中不包含 head、script、link、meta 之類不可見的節點
  • CSS 定義的樣式規則將和實際的 DOM 匹配,并且被 display:none 修飾的節點最終不會出現在渲染樹中

渲染階段

根據上圖,整個渲染階段分為三部分:

  • 渲染樹的形成:通過 DOM 和 CSSOM 形成渲染樹
  • 布局 Layout(自動重排 Reflow):基于頁面的流式布局,遍歷渲染樹節點,不斷計算節點最終的位置,幾何信息,樣式等屬性后,輸出一個“盒模型”
  • 繪制 Paint(柵格化):將節點位置,大小根據屏幕的窗口大小換算成真實的像素,同顏色等屬性一同“畫到”頁面上

回流和重繪

基本概念

  • 回流 Reflow:某些元素位置、幾何形狀的更改需要瀏覽器重新計算相關元素。
  • 重繪 Repaint:將回流重排好的元素繪制到頁面上,但也因某些 js、css 的修改導致渲染樹發生變化,瀏覽器需要再次繪制頁面。

兩者的關系:觸發回流一定會觸發重繪, 而觸發重繪卻不一定會觸發回流

下圖很形象的展示了 Mozilla 頁面的渲染過程。

觸發回流條件

  • 首次布局渲染頁面
  • 改變瀏覽器窗口大小
  • 改變字體
  • 網頁內容變化
  • 觸發 CSS 偽類
  • 操作 DOM
  • style 樣式表發生變化
  • 調用 DOM 元素的 offsetXX, clientXX,scrollXX,getClientRects 等屬性方法,獲取元素當前的位置度量信息(參見)

如何測試網頁性能

都知道頻繁的渲染過程會影響網頁性能,但怎么知道網頁開始渲染內容了呢?

我們可以通過 Chrome 的 F12,選擇 Rendering 來查看網頁的性能。

  • Paint flashing: 以綠色高亮重繪區域
  • Layout Shift Regions: 以藍色高亮布局發生變化的區域

結合上面的方法,用 一個簡單的 Demo 來示意:

能從圖中看到,這些操作 觸發了瀏覽器的重繪

  • 鼠標移至按鈕上,觸發了默認的 hover 效果(出現綠框)
  • 改變元素 color 屬性(出現綠框)
  • 修改元素 top 屬性,不斷改變元素位置影響布局(出現綠框,藍框)

提升渲染性能

布局/回流繪制/重繪 是頁面渲染必須會經過的兩個過程,不斷觸發它們肯定會增加性能的消耗。

瀏覽器會對這些操作做優化(把它們放到一個隊列,批量進行操作),但如果我們調用上面提到的 offsetXX, clientXX,scrollXX,getClientRects 等屬性方法就會強制刷新這個隊列,導致這些隊列批量優化無效。

下面列舉一些簡單優化方式:

  • 不要使用 table 布局 table 布局會破壞 HTML 流式解析過程,甚至內部元素改動會觸發整個 table 重繪
  • 將需更改的 class 放到最里層 明確元素位置,減少父類元素不必要渲染判斷
  • 使用 fixed、absolute 屬性修飾復雜多變的處理(動畫) 將改變范圍降到最低程度,避免影響到父級元素
  • 合并,減少 DOM 操作;通過虛擬 DOM 來代替

腳本的加載

link 和 script 加載文件的差異

注:均放在 head 標簽內。

考個問題:CSS 定義在 head 中,其需加載 5 秒,請問頁面加載后內容會先優先展示嗎?

我被渲染出來了

我原先以為頁面內容會優先渲染,CSS 加載完成后才改變內容樣式。其實這是錯的。

從上圖看到,頁面加載后,body 內元素就已經解析好了,只是沒有渲染到頁面上。隨后 CSS 文件加載后,帶有樣色的內容才被渲染到頁面上。

延遲的 link 的加載阻斷了頁面渲染,但并沒有影響 HTML 的解析,當 CSS 加載后,DOM 完成解析,CSSOM 和 DOM 形成渲染樹,最后將內容渲染到頁面上。

反問,將 link 替換成 script 效果也一樣嗎?

與 link 不同,script 的加載會阻斷頁面 HTML 的解析,瀏覽器解析完 script 后,會等待 js 文件加載完后,頁面才開始后續的解析,body 內容才出現。

head 和 body 中的 script 標簽

學前端時相信都聽過這樣的名言:

CSS 寫在 head 里,js 寫在 body 結束標簽前

知道了上面 link 和 script 的區別后,應該明白前半句的含義,下面來解釋下后半句。

下面 script 均在 body 中

頁面渲染 和 script 加載

先看下腳本在 body 中的一般情況:

在 body 內部的首位分別加載兩個 js 文件,前者延遲 3 秒,后者延遲 5 秒,為了清楚他們的“工作”情況,在 head 中添加了定時器示意。

我被渲染了

能看到 body 中定義的內聯腳本首先工作,初始化 foo 變量。

隨后加載 addTen.js,并阻斷頁面渲染。3 秒后,輸出 js 內容(foo 賦值為 10),頁面并重新開始解析,展示 div 內容。

最后加載 addOne.js ,繼續等待 2 秒后,輸出 js 內容(foo 賦值為 11)。

多個 script 文件的加載

如果前一個 js 文件加載慢于后一個,會有怎么個效果?

我被渲染了

兩個 script 標簽并行加載,1 秒后 addOne.js 首先加載完畢,等待 4s 秒后,addTen.js 加載完后,頁面直接渲染(因為 script 已經全部完成)。

簡單總結下

  • 無論在 head 還是 body 中,瀏覽器會等待 script 文件的加載(阻斷頁面解析渲染)
  • 多個 script 的文件加載是異步的,不存在互相影響(后一個文件不需要等待前一個加載完后才下載),執行順序同定義順序
  • 所以建議 script 放在 body 結束標簽之前,確保頁面內容全部解析完成并開始渲染。

    DOM 的 DOMContentLoaded 事件

    DOMContentLoaded 事件可以來確定整個 DOM 是否全部加載完成,下面我們簡單測試下:

    我被渲染了

    最終輸出:

    addTen.jsfoo 10addOne.jsfoo 11[ready] document

    DOMContentLoaded 事件的定義是異步回調方式,當 DOM 加載完成后觸發,即使寫在最前面,也會等待后面的 script 加載完成后才觸發。

    這里順便提個 window.onload

    window.onloadDOMContentLoaded 不同,前者會等待頁面中所有的資源加載完畢后再調用執行(比如:img 標簽),后者在 DOM 加載完畢后即觸發。

    “真正的異步腳本”——動態腳本

    能看到無論 script 放在那個位置,瀏覽器都會等待他們直至 body 內的文件全部加載完。

    那有什么 真正的異步 腳本加載嗎?(不會阻斷頁面解析)

    那就是 動態腳本

    如果你接觸過第三方網頁統計腳本,那將比較了解,下面給段示例代碼:

    我被渲染了

    最終輸出:

    addTen.jsafoo 10addOne.jsfoo 11[ready] document已加載 5 秒已加載 6 秒已加載 7 秒已加載 8 秒dynamicScript.js is runningdynamicScript.js loaded已加載 9 秒已加載 10 秒

    定義了需要加載 8 秒的 dynamicScript.js 文件,所有的 script 加載方式依舊異步,但 dynamicScript.js 在 DOMContentLoaded 觸發后,最后才執行,瀏覽器并沒有等待它的加載完成后才渲染頁面。

    我們也可以將它放在 head 中。這種通過腳本來動態修改 DOM 結構的加載方式是 無阻塞式 的,不受其他腳本加載的影響。

    defer 和 async

    我們可以在 script 定義 deferasync ,使整個腳本加載方式更加友好。比如:被修飾的腳本在 head 中,將不會阻斷 body 內容的展示

    注意: defer 修飾的腳本將延遲到 body 中所有定義的腳本之后,DOM(頁面內容)加載完之前觸發async 不會像 defer 一樣等待 body 中的腳本,而是當前腳本一加載完畢就觸發。

    我被渲染了

    加載順序:

    已加載 1 秒已加載 2 秒scriptAsync.js已加載 3 秒已加載 4 秒addTen.jsfoo 10addOne.jsfoo 11scriptDefer.js[ready] document已加載 5 秒已加載 6 秒已加載 7 秒已加載 8 秒dynamicScript.js is runningdynamicScript.js loaded已加載 9 秒已加載 10 秒

    本文使用 mdnice 排版

    總結

    以上是生活随笔為你收集整理的关闭浏览器网页触发事件_浅析浏览器渲染和 script 加载的全部內容,希望文章能夠幫你解決所遇到的問題。

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