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

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

生活随笔

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

HTML

浏览器从输入URL到页面渲染过程 ——页面渲染流程

發(fā)布時(shí)間:2024/9/27 HTML 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浏览器从输入URL到页面渲染过程 ——页面渲染流程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前我有總結(jié)過(guò)一篇經(jīng)典面試題:瀏覽器從輸入U(xiǎn)RL到頁(yè)面渲染過(guò)程 ,接下里我將對(duì)某些知識(shí)點(diǎn)進(jìn)行更細(xì)致的解析。

瀏覽器從輸入U(xiǎn)RL到頁(yè)面渲染過(guò)程 系列文章:

(一):瀏覽器從輸入U(xiǎn)RL到頁(yè)面渲染過(guò)程 —— 瀏覽器的進(jìn)程與線程

————————————————————————————————————————————————————

瀏覽器從輸入U(xiǎn)RL到頁(yè)面渲染過(guò)程 ——頁(yè)面渲染流程

瀏覽器的渲染機(jī)制很復(fù)雜,從輸入HTML到頁(yè)面輸出大致分為以下這些步驟:

構(gòu)建DOM樹(shù) > 構(gòu)建styleSheets樹(shù) > 布局 > 分層 > 繪制 >分塊 > 光柵化 > 合成

構(gòu)建DOM樹(shù)

  • 為什么要構(gòu)建 DOM 樹(shù)?

    因?yàn)闉g覽器無(wú)法直接理解和使用 HTML,所以需要將 HTML 轉(zhuǎn)換為瀏覽器能夠理解的結(jié)構(gòu)——DOM 樹(shù)。

    什么是樹(shù)結(jié)構(gòu):節(jié)點(diǎn)與節(jié)點(diǎn)之間通過(guò)父子關(guān)系相連接。

    具體流程如下:

我們?cè)赾hrome的控制臺(tái)輸入:document ,便能看到此DOM樹(shù)結(jié)構(gòu):

雖然 DOM樹(shù) 和 HTML 看起來(lái)并沒(méi)有什么的區(qū)別,但是DOM樹(shù)在內(nèi)存中是以樹(shù)狀結(jié)構(gòu)存儲(chǔ)的,可以被JS代碼所查詢操作。例如:

document.getElementsByTagName("p")[0].innerText = "black"


樣式計(jì)算(構(gòu)建styleSheets)

  • 為什么要構(gòu)建 styleSheets ?

    和 HTML 文件一樣,瀏覽器也是無(wú)法直接理解這些純文本的 CSS 樣式,所以當(dāng)渲染引擎接收到 CSS 文本時(shí),會(huì)執(zhí)行一個(gè)轉(zhuǎn)換操作,將 CSS 文本轉(zhuǎn)換為瀏覽器可以理解的結(jié)構(gòu)——styleSheets。

  • 什么是瀏覽器可以理解的style?

    rem/em ————> px
    color: blue ————> rgb(0, 0, 255)
    font-weight: blod ————> 700

  • CSS來(lái)源有哪些呢?

    1、通過(guò) link 引用的外部 CSS 文件
    2、< style >標(biāo)記內(nèi)的 CSS
    3、元素的 style 屬性內(nèi)嵌的 CSS


如果這三個(gè)地方都有對(duì)同一標(biāo)簽進(jìn)行樣式定義,或者該標(biāo)簽沒(méi)有被定義樣式,那它的最終樣式會(huì)是什么樣的呢?這時(shí)候,就需要進(jìn)行樣式計(jì)算了。

樣式計(jì)算規(guī)則:繼承規(guī)則層疊規(guī)則

繼承規(guī)則:當(dāng)前標(biāo)簽的樣式繼承了其所有父標(biāo)簽的樣式。
層疊規(guī)則:多個(gè)樣式同時(shí)作用于該標(biāo)簽時(shí),進(jìn)行樣式層疊。

當(dāng)然,我們?cè)诳刂婆_(tái)輸入 document.styleSheets 看到styleSheets結(jié)構(gòu):

布局(構(gòu)建render樹(shù))

有了 DOM樹(shù) 和 styleSheets樹(shù),接下來(lái)我們就可以將兩棵樹(shù)進(jìn)行合并,生成render樹(shù)。


在生成render樹(shù)時(shí),瀏覽器首先遍歷 DOM 樹(shù)中的所有可見(jiàn)節(jié)點(diǎn),并把這些節(jié)點(diǎn)加到布局樹(shù)中,而不可見(jiàn)的節(jié)點(diǎn)會(huì)被布局樹(shù)忽略掉,如 head 標(biāo)簽下面的全部?jī)?nèi)容,再比如 body.div.span 這個(gè)元素,因?yàn)樗膶傩园?dispaly:none,所以這個(gè)元素也沒(méi)有被包進(jìn)布局樹(shù)。

當(dāng)然,這只是第一步,光有這些標(biāo)簽和對(duì)應(yīng)的樣式是無(wú)法繪出頁(yè)面圖的,渲染進(jìn)程還需要計(jì)算出每一個(gè)標(biāo)簽所對(duì)應(yīng)在頁(yè)面上的物理位置,再將其位置存儲(chǔ)到render樹(shù)中。

分層

雖然有了render樹(shù)及對(duì)應(yīng)的物理坐標(biāo),但瀏覽器也不能直接進(jìn)行頁(yè)面繪制,因?yàn)轫?yè)面上還涉及許多復(fù)雜的樣式:transform, animation 動(dòng)畫、scroll,z-indexing改變層級(jí)等等,瀏覽器則為這些特殊的節(jié)點(diǎn)建立一個(gè)對(duì)應(yīng)圖層,生成圖層樹(shù)(LayerTree),將這些圖層合并在一起,就是一整個(gè)頁(yè)面的樣式(類似于 photoshop 的圖層)。

那什么時(shí)候會(huì)被提升為一個(gè)專門的圖層,哪些應(yīng)該被包含在同一圖層?

1、擁有層疊上下文屬性的元素

什么是層疊上下文?其實(shí)就是我們熟悉使用的z-index,MDN上是這么定義的:

其中有一句話很重要:

重要的是,其子級(jí)層疊上下文的 z-index 值只在父級(jí)中才有意義。

不知你在使用z-index時(shí),有沒(méi)有遇到這樣一個(gè)情況:

有時(shí),你想要某一個(gè)圖片或者文字 置于 某一塊 的上方,于是使用z-index進(jìn)行層級(jí)提升,但是就算設(shè)置了z-index確沒(méi)有起作用。

正式因?yàn)?子級(jí)層疊上下文的 z-index 值只在父級(jí)中才有意義 ,只有當(dāng) 父級(jí)的 position 為 absolut 或者 relative 時(shí)才有效。

2、需要剪裁的地方也會(huì)被創(chuàng)建為圖層。

當(dāng)父容器的寬高不足以撐起子容器的寬高,出現(xiàn)滾動(dòng)條 或者 設(shè)置 父容器 為overflow :hode 等等,子容器頁(yè)面就會(huì)被裁剪,這時(shí)瀏覽器也會(huì)為其創(chuàng)建出單獨(dú)的圖層。

如何查看圖層?

打開(kāi) chrome 控制臺(tái),選擇 Layers, 點(diǎn)擊旋轉(zhuǎn)按鈕,對(duì)圖層進(jìn)行拖拽到有一定的傾斜度時(shí),便能很直觀的看到頁(yè)面的圖層分布 :

繪制

創(chuàng)建完圖層后,接下來(lái)就是對(duì)圖層進(jìn)行繪制繪制,簡(jiǎn)單的說(shuō)就是將圖層重疊在一起。

如果給我們一張圖,我們會(huì)怎樣進(jìn)行繪制呢?

一般我們會(huì)對(duì)這張圖進(jìn)行拆分:

1、先畫出最外層的紅色框圖
2、在畫出中間層綠色框圖
3、最后畫出里面層黃色框圖

瀏覽器也是如此,將這些圖層拆分為一條條的指令,然后一條一條逐步執(zhí)行,最后進(jìn)行繪制:

分塊

為什么需要分塊? 再此之前我們需要了解一下什么是視口:我們?cè)诋?dāng)前屏幕區(qū)域能看到的模塊就叫視口。當(dāng)頁(yè)面內(nèi)容很長(zhǎng)時(shí),頁(yè)面就會(huì)出現(xiàn)滾動(dòng)條,但是當(dāng)前視口大小有限,我們只能看到一部分,所以在這種情況下,要繪制出所有圖層內(nèi)容的話,就會(huì)產(chǎn)生太大的開(kāi)銷,而且也沒(méi)有必要。

這個(gè)時(shí)候渲染進(jìn)程會(huì)再次將這些圖層分成很多圖塊。

格珊化

什么是格珊化?

渲染進(jìn)程將這些圖層分成很多圖塊后,然后按照視口附近的圖塊來(lái)通過(guò) 柵格化 優(yōu)先生成位圖。所謂柵格化,是指將圖塊轉(zhuǎn)換為位圖。而圖塊是柵格化執(zhí)行的最小單位。

最后,我們來(lái)看一張流程圖:

之前的生成DOM樹(shù)、styleSheets樹(shù)、render 樹(shù)、分層、繪制都是在渲染引起的主線程中運(yùn)行的, 繪制列表記錄好繪制順序和繪制指令的列表后,將其提交給渲染引擎中的合成線程,渲染進(jìn)程還維護(hù)了一個(gè)柵格化的線程池,所有的圖塊柵格化都是在線程池內(nèi)執(zhí)行的。通常,柵格化過(guò)程都會(huì)使用 GPU 來(lái)加速生成,使用 GPU 生成位圖的過(guò)程叫快速柵格化,或者 GPU 柵格化,生成的位圖被保存在 GPU 內(nèi)存中。

合成與顯示

一旦所有圖塊都被光柵化,合成線程就會(huì)生成一個(gè)繪制圖塊的命令——“DrawQuad”,然后將該命令提交給瀏覽器進(jìn)程。瀏覽器進(jìn)程里面有一個(gè)叫 viz 的組件,用來(lái)接收合成線程發(fā)過(guò)來(lái)的 DrawQuad 命令,然后根據(jù) DrawQuad 命令,將其頁(yè)面內(nèi)容繪制到內(nèi)存中,最后再將內(nèi)存顯示在屏幕上。

至此,整個(gè)渲染流程就走完了,總結(jié)為以下8步:

1、渲染進(jìn)程將 HTML 內(nèi)容轉(zhuǎn)換為能夠讀懂的 DOM 樹(shù)結(jié)構(gòu)。
2、渲染引擎將 CSS 樣式表轉(zhuǎn)化為瀏覽器可以理解的 styleSheets樹(shù),并計(jì)算好 DOM 節(jié)點(diǎn)的樣式。
3、將DOM與styleSheets樹(shù)進(jìn)行合成,創(chuàng)建布局(render)樹(shù),并計(jì)算元素的布局信息。
4、對(duì)布局樹(shù)進(jìn)行分層,并生成分層樹(shù)。為每個(gè)圖層生成繪制列表,并將其提交到合成線程。
5、合成線程將圖層分成圖塊。
6、在光柵化線程池中將圖塊轉(zhuǎn)換成位圖。
7、合成線程發(fā)送繪制圖塊命令 DrawQuad 給瀏覽器進(jìn)程。
8、瀏覽器進(jìn)程根據(jù) DrawQuad 消息生成頁(yè)面,并顯示到顯示器上。

最后拋出兩個(gè)問(wèn)題:

1、為什么在優(yōu)化 Web 性能的方法中,減少重繪、重排是一種很好的優(yōu)化方式?

結(jié)合上文我們了解到,在布局這一過(guò)程中,將DOM樹(shù)與styleSheets 合成render樹(shù)后,渲染進(jìn)程還需要計(jì)算出每一個(gè)標(biāo)簽所對(duì)應(yīng)在頁(yè)面上的物理位置,再將其位置存儲(chǔ)到render樹(shù)中,在執(zhí)行下一步。

如果我們對(duì)頁(yè)面進(jìn)行了重排(改變標(biāo)簽的寬高、顯示隱藏等物理層面的幾何屬性),那么渲染引擎將會(huì)把這一整套渲染流程重新跑一遍,浪費(fèi)時(shí)間和空間。

如果我們對(duì)頁(yè)面進(jìn)行了重繪(改變標(biāo)簽的顏色、類名等樣式屬性),那么渲染引擎會(huì)直接進(jìn)入 繪制 階段,相較與重排,也提升了不少性能。

如果我們的操作不涉及重排和重繪,那么渲染引擎會(huì)直接進(jìn)入 合成 階段,大大的提高了性能。

2、如果下載 CSS/JS 文件阻塞了,會(huì)阻塞 DOM 樹(shù)的合成嗎?會(huì)阻塞頁(yè)面的顯示嗎?

答案是肯定的,不論CSS還是JS文件下載阻塞,都會(huì)阻塞后續(xù)的流程。當(dāng)從服務(wù)器接收HTML頁(yè)面的第一批數(shù)據(jù)時(shí),DOM解析器就開(kāi)始工作了。
第一種情況:在解析過(guò)程中,如果遇到了JS腳本,如下所示:

<html><body>哈哈哈<script>document.write("--限制性js腳本")</script></body> </html>

那么DOM解析器會(huì)先執(zhí)行JavaScript腳本,執(zhí)行完成之后,再繼續(xù)往下解析。

第二種情況:我們內(nèi)聯(lián)的腳本替換成js外部文件,如下所示:

<html><body>哈哈哈<script type="text/javascript" src="foo.js"></script></body> </html>

這種情況下,當(dāng)解析到JavaScript的時(shí)候,會(huì)先暫停DOM解析,并下載foo.js文件,下載完成之后執(zhí)行該段JS文件,然后再繼續(xù)往下解析DOM。這就是JavaScript文件為什么會(huì)阻塞DOM渲染。

第三種情況,還是看下面代碼:

<html><head><style type="text/css" src = "theme.css" /></head><body><p>哈哈哈</p><script>let e = document.getElementsByTagName('p')[0]e.style.color = 'blue'</script></body> </html>

當(dāng)我在JavaScript中訪問(wèn)了某個(gè)元素的樣式,那么這時(shí)候就需要等待這個(gè)樣式被下載完成才能繼續(xù)往下執(zhí)行,所以在這種情況下,CSS也會(huì)阻塞DOM的解析。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的浏览器从输入URL到页面渲染过程 ——页面渲染流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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