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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > HTML >内容正文

HTML

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

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

前言

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

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

借著這篇文章,讓自己對(duì)這塊知識(shí)的理解更深一步。

渲染

渲染樹(Render Tree)

瀏覽器通過(guò)解析 HTML 和 CSS 后,形成對(duì)應(yīng)的 DOM 樹和 CSSOM 樹。

從根節(jié)點(diǎn)開始解析 DOM 樹節(jié)點(diǎn)并匹配對(duì)應(yīng)的 CSSOM 樣式規(guī)則,選擇可見(jiàn)的的節(jié)點(diǎn),最終結(jié)合成一顆渲染樹

從上圖能看到渲染樹的特點(diǎn):

  • 渲染樹中不包含 head、script、link、meta 之類不可見(jiàn)的節(jié)點(diǎn)
  • CSS 定義的樣式規(guī)則將和實(shí)際的 DOM 匹配,并且被 display:none 修飾的節(jié)點(diǎn)最終不會(huì)出現(xiàn)在渲染樹中

渲染階段

根據(jù)上圖,整個(gè)渲染階段分為三部分:

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

回流和重繪

基本概念

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

兩者的關(guān)系:觸發(fā)回流一定會(huì)觸發(fā)重繪, 而觸發(fā)重繪卻不一定會(huì)觸發(fā)回流

下圖很形象的展示了 Mozilla 頁(yè)面的渲染過(guò)程。

觸發(fā)回流條件

  • 首次布局渲染頁(yè)面
  • 改變?yōu)g覽器窗口大小
  • 改變字體
  • 網(wǎng)頁(yè)內(nèi)容變化
  • 觸發(fā) CSS 偽類
  • 操作 DOM
  • style 樣式表發(fā)生變化
  • 調(diào)用 DOM 元素的 offsetXX, clientXX,scrollXX,getClientRects 等屬性方法,獲取元素當(dāng)前的位置度量信息(參見(jiàn))

如何測(cè)試網(wǎng)頁(yè)性能

都知道頻繁的渲染過(guò)程會(huì)影響網(wǎng)頁(yè)性能,但怎么知道網(wǎng)頁(yè)開始渲染內(nèi)容了呢?

我們可以通過(guò) Chrome 的 F12,選擇 Rendering 來(lái)查看網(wǎng)頁(yè)的性能。

  • Paint flashing: 以綠色高亮重繪區(qū)域
  • Layout Shift Regions: 以藍(lán)色高亮布局發(fā)生變化的區(qū)域

結(jié)合上面的方法,用 一個(gè)簡(jiǎn)單的 Demo 來(lái)示意:

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

  • 鼠標(biāo)移至按鈕上,觸發(fā)了默認(rèn)的 hover 效果(出現(xiàn)綠框)
  • 改變?cè)?color 屬性(出現(xiàn)綠框)
  • 修改元素 top 屬性,不斷改變?cè)匚恢糜绊懖季?出現(xiàn)綠框,藍(lán)框)

提升渲染性能

布局/回流繪制/重繪 是頁(yè)面渲染必須會(huì)經(jīng)過(guò)的兩個(gè)過(guò)程,不斷觸發(fā)它們肯定會(huì)增加性能的消耗。

瀏覽器會(huì)對(duì)這些操作做優(yōu)化(把它們放到一個(gè)隊(duì)列,批量進(jìn)行操作),但如果我們調(diào)用上面提到的 offsetXX, clientXX,scrollXX,getClientRects 等屬性方法就會(huì)強(qiáng)制刷新這個(gè)隊(duì)列,導(dǎo)致這些隊(duì)列批量?jī)?yōu)化無(wú)效。

下面列舉一些簡(jiǎn)單優(yōu)化方式:

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

腳本的加載

link 和 script 加載文件的差異

注:均放在 head 標(biāo)簽內(nèi)。

考個(gè)問(wèn)題:CSS 定義在 head 中,其需加載 5 秒,請(qǐng)問(wèn)頁(yè)面加載后內(nèi)容會(huì)先優(yōu)先展示嗎?

我被渲染出來(lái)了

我原先以為頁(yè)面內(nèi)容會(huì)優(yōu)先渲染,CSS 加載完成后才改變內(nèi)容樣式。其實(shí)這是錯(cuò)的。

從上圖看到,頁(yè)面加載后,body 內(nèi)元素就已經(jīng)解析好了,只是沒(méi)有渲染到頁(yè)面上。隨后 CSS 文件加載后,帶有樣色的內(nèi)容才被渲染到頁(yè)面上。

延遲的 link 的加載阻斷了頁(yè)面渲染,但并沒(méi)有影響 HTML 的解析,當(dāng) CSS 加載后,DOM 完成解析,CSSOM 和 DOM 形成渲染樹,最后將內(nèi)容渲染到頁(yè)面上。

反問(wèn),將 link 替換成 script 效果也一樣嗎?

與 link 不同,script 的加載會(huì)阻斷頁(yè)面 HTML 的解析,瀏覽器解析完 script 后,會(huì)等待 js 文件加載完后,頁(yè)面才開始后續(xù)的解析,body 內(nèi)容才出現(xiàn)。

head 和 body 中的 script 標(biāo)簽

學(xué)前端時(shí)相信都聽過(guò)這樣的名言:

CSS 寫在 head 里,js 寫在 body 結(jié)束標(biāo)簽前

知道了上面 link 和 script 的區(qū)別后,應(yīng)該明白前半句的含義,下面來(lái)解釋下后半句。

下面 script 均在 body 中

頁(yè)面渲染 和 script 加載

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

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

我被渲染了

能看到 body 中定義的內(nèi)聯(lián)腳本首先工作,初始化 foo 變量。

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

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

多個(gè) script 文件的加載

如果前一個(gè) js 文件加載慢于后一個(gè),會(huì)有怎么個(gè)效果?

我被渲染了

兩個(gè) script 標(biāo)簽并行加載,1 秒后 addOne.js 首先加載完畢,等待 4s 秒后,addTen.js 加載完后,頁(yè)面直接渲染(因?yàn)?script 已經(jīng)全部完成)。

簡(jiǎn)單總結(jié)下

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

    DOM 的 DOMContentLoaded 事件

    DOMContentLoaded 事件可以來(lái)確定整個(gè) DOM 是否全部加載完成,下面我們簡(jiǎn)單測(cè)試下:

    我被渲染了

    最終輸出:

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

    DOMContentLoaded 事件的定義是異步回調(diào)方式,當(dāng) DOM 加載完成后觸發(fā),即使寫在最前面,也會(huì)等待后面的 script 加載完成后才觸發(fā)。

    這里順便提個(gè) window.onload

    window.onloadDOMContentLoaded 不同,前者會(huì)等待頁(yè)面中所有的資源加載完畢后再調(diào)用執(zhí)行(比如:img 標(biāo)簽),后者在 DOM 加載完畢后即觸發(fā)。

    “真正的異步腳本”——?jiǎng)討B(tài)腳本

    能看到無(wú)論 script 放在那個(gè)位置,瀏覽器都會(huì)等待他們直至 body 內(nèi)的文件全部加載完。

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

    那就是 動(dòng)態(tài)腳本

    如果你接觸過(guò)第三方網(wǎng)頁(yè)統(tǒng)計(jì)腳本,那將比較了解,下面給段示例代碼:

    我被渲染了

    最終輸出:

    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 觸發(fā)后,最后才執(zhí)行,瀏覽器并沒(méi)有等待它的加載完成后才渲染頁(yè)面。

    我們也可以將它放在 head 中。這種通過(guò)腳本來(lái)動(dòng)態(tài)修改 DOM 結(jié)構(gòu)的加載方式是 無(wú)阻塞式 的,不受其他腳本加載的影響。

    defer 和 async

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

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

    我被渲染了

    加載順序:

    已加載 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 排版

    總結(jié)

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

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。