成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

圖解Chrome:HTML/CSS/JS是如何在瀏覽器中,渲染成你看到的頁面?

開發(fā) 開發(fā)工具
Chrome 算是程序員的標配了,從全球的市場份額來看,它在全球市場的份額已經(jīng)超過 60%。

Chrome 算是程序員的標配了,從全球的市場份額來看,它在全球市場的份額已經(jīng)超過 60%。

在 Chrome 10 周年之際,官方發(fā)布了一個系列文章,用圖解的方式,很清晰的講解了現(xiàn)代瀏覽器的運行原理。

渲染器進程的內(nèi)部工作原理

本系列分為 4 個部分,主要講解關(guān)于現(xiàn)代瀏覽器的運行原理,本文為該系列的第 3 篇。在之前的文章中,我們介紹了多進程架構(gòu)和導(dǎo)航的完整流程,而在這篇文章中,我們將探究在渲染器進程的內(nèi)部,到底發(fā)生了什么。

渲染器進程涉及到 Web 性能相關(guān)的多個方面,由于渲染器進程中處理了很多的邏輯,不是一篇文章可以全面講解的,因此本文僅作為一個概述。如果你有興趣深入研究,可以在《Why Performance Matters》這篇文章里找到更多的資料。

渲染器進程處理Web內(nèi)容

所有選項卡內(nèi)發(fā)生的邏輯,都由渲染器進程負責(zé)。在渲染器進程中,主線程處理了服務(wù)器發(fā)送給用戶的大部分代碼。如果你使用到 Web Workder 或者Service Worker,那 JavaScript 中的這部分代碼,將由工作線程處理。Compositor(合成器) 和 Raster(光柵) 線程也在渲染器內(nèi)運行,從而實現(xiàn)高效、流暢的渲染頁面。

渲染器進程的核心工作是將 HTML,CSS 和 JavaScript 轉(zhuǎn)換為用戶可以與之交互的網(wǎng)頁。

上圖中,描述了具有主線程、工作線程、Compositor 線程、Raster 線程的渲染器進程,以及他們之間的關(guān)系。

解析

構(gòu)建 DOM

當渲染器進程收到一個導(dǎo)航請求,并開始接收 HTML 數(shù)據(jù),主線程將開始處理文本字符串(HTML),將其解析成 DOM(Document Object Model)。

DOM 是 Web 頁面的內(nèi)部的邏輯樹文檔結(jié)構(gòu),Web 開發(fā)人員可以通過 JavaScript 腳本與之交互數(shù)據(jù),以及通過標準 API 來操作 DOM 節(jié)點。

將 HTML 文檔解析成 DOM 是完全依照于 HTML 協(xié)議。并且在 HTML 協(xié)議中,瀏覽器不會對錯誤的 HTML 進行錯誤提示。例如,缺少結(jié)束的 </p> 標簽時,這依然是一個有效的 HTML。類似 Hi! <b>I'm <i>Chrome</b>!</i> 中,b 標簽在 i 標簽之前關(guān)閉這樣的錯誤,會被 HTML 理解為 Hi! <b>I'm <i>Chrome</i></b><i>!</i>。這是因為 HTML 規(guī)范的主要原則是優(yōu)雅的處理這些錯誤,而不是嚴格檢查。

如果你對這些規(guī)范感到好奇,可以閱讀 HTML 規(guī)范中的 “解析器中的錯誤處理和奇怪案例介紹” 部分。

解析器中的錯誤處理和奇怪案例介紹:

https://html.spec.whatwg.org/multipage/parsing.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser

子資源加載

一個完整的 Web 站點通常會包含圖片、CSS 和 JS 等外部資源,這些文件都需要從網(wǎng)絡(luò)或者本地緩存中加載。主線程可以在解析構(gòu)建 DOM 的時候,將他們逐個請求,但是為了加快速度,會同時使用 “預(yù)加載掃描(Preload Scanner)”。

如果 “預(yù)加載掃描” 發(fā)現(xiàn)有類似 <img> 或 <link> 這樣的標簽時,會由 HTML 解析器對該資源生成一個 Tokens,然后在瀏覽器進程中,通過網(wǎng)絡(luò)或者本地緩存來加載資源。

上圖描述了,主線程解析 HTML 并構(gòu)建 DOM 樹的過程。

JS 可以阻止解析

當 HTML 解析器遇到 <script> 標簽的時候,它會暫停解析 HTML 文檔,然后對這個 JS 腳本進行加載、解析和執(zhí)行。

這么設(shè)計的原因,是因為 JS 可以使用類似 document.write() 方法來改變 DOM 的結(jié)構(gòu)。這就是 HTML 解析器在重新解析 HTML 之前,必須等待 JS 腳本執(zhí)行的原因。

如果你對 JS 執(zhí)行中發(fā)生的事情細節(jié)有興趣,V8 團隊有一篇文章深入的對此進行了講解,有興趣可以看看。

V8 團隊深入研究:

https://mathiasbynens.be/notes/shapes-ics

提示瀏覽器如何加載資源

HTML 遇到 JS 腳本則暫停對 HTML 的解析,這并不是絕對的。

Web 開發(fā)人員可以通過多種方式的配置,告知瀏覽器如何更優(yōu)雅的加載資源。如果你的 JS 腳本中,沒有使用到類似 document.write() 這樣的方法,你可以在 script 標簽中添加 async 或 defer 標記,然后瀏覽器會異步加載和運行此 JS 腳本,不會阻斷解析。如果需要,也可以使用 JavaScript Modules,還可以通過 <link rel="preload"> 標簽向瀏覽器明確標記此為重要的資源,將在頁面加載完成之后被立刻使用,對于這類資源,它會在頁面加載生命周期的早期,被優(yōu)先加載。

樣式渲染(Style)

僅僅解析成 DOM,還不足以完成頁面渲染,因為還可以通過在 CSS 中,設(shè)置元素的樣式來豐富渲染效果。

主線程將解析 CSS,并將效果渲染到指定的 DOM 節(jié)點上,關(guān)于 CSS 選擇器如何定位到指定的 DOM 節(jié)點,可以通過 DevTools 來查看相關(guān)信息。

上圖中,主線程解析 CSS 并添加渲染樣式。

即使你不使用任何 CSS 樣式,每個 DOM 節(jié)點依然存在默認的渲染樣式。例如,h1 標簽在視覺上就大于 h2 標簽,并且每個元素還有默認的邊距。這是因為瀏覽器具有默認樣式表。

如果你對 Chrome 的默認 CSS 是什么樣的有興趣,可以在源碼中看到具體細節(jié)。

Chrome 的默認 CSS:

https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/css/html.css

布局(Layout)

到現(xiàn)在,渲染器進程知道每個 DOM 的結(jié)構(gòu)和樣式了,但是這依然不足以渲染頁面。想象一下,你正視圖通過文字向朋友描述一副畫,“有一個大的紅色圓圈和一個小的藍色方塊”,這些信息不足以讓你的朋友還原這幅畫。

這就牽扯到布局(Layout),布局是對元素定位的過程,主線程遍歷 DOM 并計算樣式,然后創(chuàng)建布局樹(Layout Tree),在布局樹中,包含 X、Y 坐標和邊框大小等信息。布局樹是一個與 DOM 樹類似的結(jié)構(gòu),但是它僅僅包含了頁面上可見內(nèi)容相關(guān)的信息。

舉個例子,如果某個元素設(shè)置了 display:none,則該元素將不會出現(xiàn)在布局樹中,但是它會出現(xiàn)在 DOM 樹中,而如果該元素被設(shè)置為 visibility:hidden 則它會存在于布局樹中。類似的例子還有 p::before{content:"Hi!"}  這樣的偽類,它會存在于布局樹中,而不會存在于 DOM 樹中。

如上圖所示,在主線程中渲染樣式,并生成布局樹和 DOM 樹。

計算頁面布局是一個很復(fù)雜的工作,即使最簡單的從上到下的塊流結(jié)構(gòu),也必須考慮字體的大小以及如何劃分每一塊,因為它們會影響當前段落的大小和形狀,然后影響下一塊所在的位置。

CSS 樣式可以設(shè)置元素浮動到某一側(cè)、隱藏 overflow 的元素,或者改變排版方向。布局是一個非常復(fù)雜的工作,在 Chrome 中,有一個完整的工程師團隊負責(zé)布局。如果你的對他們工作的細節(jié)感興趣,可以參閱 BinkOn 會議的記錄。

BinkOn:

https://www.youtube.com/watch?v=Y5Xa4H2wtVA

繪制(Paint)

擁有 DOM、CSS 和 LayoutTree 仍然不足以渲染頁面。假設(shè)你正在嘗試重繪一幅畫,你除了需要知道元素的大小、外觀和位置之外,還需要知道它們的繪制順序。

例如:z-index 屬性將改變元素的層級,在這種情況下,按 HTML 中編寫的元素順序進行繪制,將導(dǎo)致渲染結(jié)果和預(yù)期不符。

如上圖所示,因為沒有正確的考慮 z-index,將導(dǎo)致頁面被錯誤的渲染。

在這個繪制的過程中,主線程遍歷布局樹,然后創(chuàng)建繪制記錄。繪制記錄是一個繪制過程的注釋,例如“背景優(yōu)先,然后是文本,***是矩形”。如果你曾經(jīng)使用 JS 在 <canvas> 上繪制元素,那么你對此過程應(yīng)該會很熟悉。

如上圖所示,主線程遍歷布局樹,并生成繪制記錄。

更新渲染管道的成本很高

渲染管道(Rendering Pipeline)中最重要的任務(wù),就是在每個步驟開始前,根據(jù)前一次操作的結(jié)果,來創(chuàng)建新的數(shù)據(jù)。例如,如果布局樹中的某些內(nèi)容發(fā)生更改,則需要為文檔的受影響部分重新生成“繪制”順序。

渲染管道(Rendering Pipeline)中最重要的任務(wù),就是在每個步驟開始前,根據(jù)前一次操作的結(jié)果,來創(chuàng)建新的數(shù)據(jù)。例如,如果布局樹中的某些內(nèi)容發(fā)生變動,則需要為文檔中受影響的部分,重新生成“繪制記錄”。

為元素設(shè)置的動畫,瀏覽器必須在每一幀之間執(zhí)行這些操作。我們大多數(shù)顯示器每秒刷新 60 次(60fps),如果你對每一幀都做了處理,那動畫對人眼而言就是平滑的,但是如果某些幀沒有被處理到或者丟失了,則會導(dǎo)致動畫不連貫,出現(xiàn)頁面的“卡頓”。

哪怕渲染的計算可以跟上屏幕刷新,可因為此計算過程發(fā)生在主線程上,當執(zhí)行 JavaScript 腳本時,可能導(dǎo)致渲染過程被阻斷。

即使渲染的計算可以跟上屏幕的刷新速度,可因為此計算是在主線程上執(zhí)行的,這就意味著 JS 代碼的執(zhí)行,也可能導(dǎo)致它被阻斷。

如上圖,時間軸上的動畫幀,被 JS 阻止了一幀。

為此,你可以將 JavaScript 操作劃分成小塊,并在每幀上執(zhí)行requestAnimationFrame(),還可以在 Web Workers 中運行 JavaScript,以避免阻塞主線程。

如圖所示,在動畫幀的時間軸上,運行較小的 JavaScript 塊。

合成(Compositing)

如何繪制一個頁面?

現(xiàn)在瀏覽器知道文檔的結(jié)構(gòu),每個元素的樣式,頁面的形狀和繪制順序,它是如何繪制頁面的?將此信息轉(zhuǎn)換為屏幕上的像素稱為光柵化(rasterizing)。

光柵化是將幾何數(shù)據(jù)經(jīng)過一系列變換后最終轉(zhuǎn)換為像素,從而呈現(xiàn)在顯示設(shè)備上的過程。

也許處理這種情況的一種無腦方案,是在視口(ViewPort)內(nèi)部將每個組件都光柵化。如果用戶滾動頁面,則移動光柵幀,并通過更多光柵元素填充缺少的部分。

這就是 Chrome ***發(fā)布時處理光柵化的方式,但是,現(xiàn)代瀏覽器運行一個更復(fù)雜的被稱為合成(Compositing)的進程。

什么是合成(Compositing)

合成是一種將頁面的各個元素進行分層,分別光柵化,并在合成器線程中以一個單獨的線程合成新頁面的技術(shù)。如果頁面發(fā)生滾動,由于圖層已經(jīng)光柵化,因此它需要做的就是合成一個新幀。通過移動圖層同時合成新幀,可以以相同的方式實現(xiàn)動畫。

你可以在 DevTools 中的 Layout panel 來查看看圖層。

分層

為了確定每個元素所在的層,主線程遍歷布局樹以創(chuàng)建層樹(Layer Tree)。如果頁面的某元素應(yīng)該是一個單獨的圖層(例如側(cè)滑菜單),那么你可以在 CSS 中,使用 will-change 屬性提示瀏覽器。

如上圖,在主線程中遍歷布局樹,并生成層樹。

雖然理想情況下,應(yīng)該為每個元素生成圖層,但是對過多的小圖層進行合并,可能會比對頁面的每幀上柵格化小元素更慢,因此測量應(yīng)用程序的渲染性能就非常重要。有關(guān)主題的更多信息,請參閱 Stick to Compositor-Only Properties 和 Manage Layer Count。

Stick to Compositor-Only Properties 和 Manage Layer Count:

https://developers.google.com/web/fundamentals/performance/rendering/stick-to-compositor-only-properties-and-manage-layer-count

光柵和合成,脫離主線程

一旦創(chuàng)建了層樹并確定了繪制順序,主線程就會將該信息提交給合成器線程。合成器線程會光柵化每個圖層,一個圖層可能想一個完整的頁面那么大,因此合成器線程將他們分成圖塊,并將每個圖塊發(fā)送到光柵線程。光柵線程格式化每個元素,并將他們存儲在 GPU 內(nèi)存中。

圖17:光柵線程創(chuàng)建光柵位圖并發(fā)送到GPU

合成器線程可以優(yōu)先考慮不同的光柵線程,以便 ViewPort(或附近)的元素可以被優(yōu)先光柵化。圖層還具有多個不同分辨率的傾斜度,以便對內(nèi)容的放大等操作。

一旦元素被光柵化,合成器線程會收集被稱為 “繪制矩形(Draw Quads)” 的信息,用以創(chuàng)建一個合成幀(Compositor Frame)。

然后通過 IPC 將合成幀提交給瀏覽器進程。此時,可以從 UI 線程添加另一個合成幀用于瀏覽器的 UI 更新,或者從其他渲染器進程中添加擴展。這些合成幀被發(fā)送到 GPU 中,用以在屏幕上顯示。如果觸發(fā)滾動事件,合成器線程會創(chuàng)建另一個合成幀發(fā)送到 GPU。

上圖中,合成器線程創(chuàng)建合成幀。將此幀發(fā)送到瀏覽器進程然后發(fā)送到 GPU。

合成(Compositor)的好處,是它可以在不影響主線程的情況下完成。合成器線程不需要等待樣式計算或者 JS 腳本執(zhí)行,這就是為什么 “僅合成動畫” 被認為是平滑性能的***選擇。如果需要再次計算不會或者重新繪制,則必須涉及到主線程。

合成動畫:

https://www.html5rocks.com/en/tutorials/speed/high-performance-animations/

小結(jié)

在這篇文章中,我們研究了從解析到合成的渲染流程,希望你現(xiàn)在有興趣探究有關(guān)網(wǎng)站性能優(yōu)化的更多內(nèi)容。

在下一篇文章中,將更詳細的介紹合成器線程,并解釋當用戶觸發(fā) mouse move 和 click 時,會發(fā)生什么。

【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號聯(lián)系作者獲取授權(quán)】

 

戳這里,看該作者更多好文

 

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2019-04-08 10:27:00

渲染瀏覽器DOM

2017-02-16 19:09:56

Kali LinuxGoogle Chro瀏覽器

2022-08-30 09:01:11

瀏覽器渲染前端

2020-11-25 09:47:11

FedoraGoogle Chro瀏覽器

2013-11-18 14:42:53

瀏覽器渲染

2013-11-20 10:47:57

瀏覽器渲染html

2013-11-20 13:04:41

css瀏覽器渲染

2018-01-19 14:39:53

瀏覽器頁面優(yōu)化

2016-08-03 15:21:03

UbuntuLinux易用性

2020-04-21 14:00:25

HTMLCSSJS

2017-02-08 14:30:08

Chrome密碼瀏覽器

2012-10-29 09:40:43

HTML5JavaScriptWebGL

2013-11-18 15:09:34

瀏覽器渲染速度

2020-10-30 10:15:21

Chrome V8JavaScript前端

2020-11-06 15:20:45

瀏覽器前端架構(gòu)

2013-10-28 16:15:01

ChromeFirefoxIE

2021-10-19 06:01:24

Chrome瀏覽器網(wǎng)頁瀏覽器

2022-01-11 20:42:28

CSS Chrome瀏覽器

2019-04-24 17:05:51

Windows 10ChromeFirefox

2022-07-07 07:22:01

瀏覽器JavaScript工具
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产亚洲www | 欧美日韩不卡 | 国产福利在线免费观看 | 亚洲精品一区二区 | 涩涩片影院 | 国产精品久久久久久久久久 | 蜜桃av鲁一鲁一鲁一鲁 | 日韩久久网 | 一级大黄色片 | 在线观看国产www | 一区二区在线免费观看 | 欧洲视频一区二区 | 久久中文字幕视频 | 99亚洲综合 | 亚洲精品一区中文字幕乱码 | 亚洲成人免费在线 | 亚洲精品乱 | 黄色av免费网站 | 亚洲福利网 | 日日干日日色 | 亚洲视频中文字幕 | 成人亚洲综合 | 免费三级网站 | 国产黄色在线观看 | 成人依人 | 亚洲成年影院 | 成人av一区二区三区 | 正在播放国产精品 | 久久精品在线 | 日韩精品一区二区三区四区 | 国产精品观看 | 免费观看一级特黄欧美大片 | 久久国产综合 | 91成人免费看片 | 亚洲视频在线观看 | 精品国产乱码久久久久久蜜臀 | 妞干网av | 天堂在线www | 成人av免费| 成人精品一区亚洲午夜久久久 | 国产激情视频 |