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

歡迎訪問 生活随笔!

生活随笔

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

HTML

简略图解:输入 url 到出现页面,浏览器做了什么?

發(fā)布時(shí)間:2024/4/11 HTML 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简略图解:输入 url 到出现页面,浏览器做了什么? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

應(yīng)該有很多前端開發(fā)人員都思考過這么一個(gè)問題:從輸入 URL 到頁面加載完成,中間都做發(fā)生了什么?

這個(gè)問題涉及的面非常廣,每個(gè)涉及的點(diǎn)又很深入。從觸屏/鍵盤如何到 CPU?CPU 如何到系統(tǒng)內(nèi)核?如何從操作系統(tǒng) GUI 到瀏覽器?瀏覽器如何向網(wǎng)卡發(fā)送數(shù)據(jù)?數(shù)據(jù)如何從本機(jī)網(wǎng)卡發(fā)送到服務(wù)器?服務(wù)器接收數(shù)據(jù)后如何處理?服務(wù)器返回?cái)?shù)據(jù)后瀏覽器如何處理?瀏覽器如何將頁面展現(xiàn)出來?等等等等,每一個(gè)過程都包含了大量且深入的知識體系,很難一以貫通。

但作為前端開發(fā)人員,瀏覽器是我們的主要工具之一,瀏覽器是如何將頁面展現(xiàn)出來的則是我們更關(guān)注的部分。因此本文就從一些基本流程來簡要描述這個(gè)過程。

從上面這個(gè)圖中可以發(fā)現(xiàn),雖然使用的 Javascript 是單線程語言,但瀏覽器本身是多進(jìn)程的。

但是這并不是從一而終的狀態(tài),而是瀏覽器從早期的單進(jìn)程結(jié)構(gòu)逐漸發(fā)展發(fā)展而來。現(xiàn)代瀏覽器各進(jìn)程根據(jù)負(fù)責(zé)的功能不同,分為瀏覽器進(jìn)程、渲染器進(jìn)程、網(wǎng)絡(luò)進(jìn)程、GPU 進(jìn)程、緩存進(jìn)程、插件進(jìn)程等等。為了更好的理解瀏覽器頁面的呈現(xiàn)過程,我們以最主流的 Chrome 為例,簡要的說明一下各個(gè)進(jìn)程的大致職能:

  • 瀏覽器進(jìn)程: 負(fù)責(zé)控制界面展示、用戶交互、子進(jìn)程管理等功能。

  • 渲染器進(jìn)程: 負(fù)責(zé)將 HTML\CSS\JS 轉(zhuǎn)化為用戶可以與之交互的網(wǎng)頁。渲染引擎如 webkit、blink 和 JS 引擎 V8 都是在該進(jìn)程之中。

  • GPU 進(jìn)程: GPU 進(jìn)程原本是為了實(shí)現(xiàn) 3D CSS 效果,但是隨后頁面、Chrome 的 UI 都采用 GPU 來繪制,是 GPU 成為了重要需求,于是增加了 GPU 進(jìn)程。

  • 網(wǎng)絡(luò)進(jìn)程: 負(fù)責(zé)頁面的網(wǎng)絡(luò)資源加載。

  • 插件進(jìn)程:負(fù)責(zé)插件的運(yùn)行,由于插件可能崩潰,需要插件進(jìn)程其他進(jìn)程隔離。注意,插件并不是我們常用的瀏覽器拓展,plugin 和 extension 是不同的。

  • 緩存進(jìn)程:負(fù)責(zé)處理頁面資源緩存和清理。

我們本次需要重點(diǎn)關(guān)注的是渲染器進(jìn)程。

回到問題,當(dāng)我們在瀏覽器地址欄輸入地址時(shí),瀏覽器進(jìn)程的 UI 線程會捕捉輸入內(nèi)容,如果訪問的是網(wǎng)址,那么 UI 線程會啟動(dòng)一個(gè)網(wǎng)絡(luò)線程來構(gòu)建請求(這里我們暫時(shí)不考慮緩存,緩存又是另外一個(gè)故事了),它請求 DNS 進(jìn)行域名解析然后連接服務(wù)器獲取數(shù)據(jù)。如果我們輸入的是關(guān)鍵詞,瀏覽器則使用默認(rèn)配置的搜索引擎來搜索。在獲取到數(shù)據(jù)并通過安全校驗(yàn)后,網(wǎng)絡(luò)線程會通知 UI 線程數(shù)據(jù)準(zhǔn)備完畢,然后UI線程創(chuàng)建一個(gè)渲染器進(jìn)程來進(jìn)行頁面的渲染,并將數(shù)據(jù)通過 IPC 管道傳遞給渲染器進(jìn)程。

至此,我們的主角渲染器進(jìn)程登場!

解析 HTML

渲染器進(jìn)程接收到的是一個(gè) HTML,需要把 HTML 解析成 DOM 數(shù)據(jù)結(jié)構(gòu)。因?yàn)橹苯拥?HTML 字節(jié)流是無法被渲染引擎所理解的,必須轉(zhuǎn)化成可以理解的內(nèi)部結(jié)構(gòu)。這個(gè)內(nèi)部結(jié)構(gòu)就是 DOM,DOM 提供了對 HTML 文檔的結(jié)構(gòu)化表述。在渲染引擎中,DOM 有三個(gè)層面的作用:

  • 從頁面角度:DOM 是生成頁面的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)。

  • 從 js 角度:DOM 提供了 js 操作的接口。通過這套接口,js 可以對 DOM 接口進(jìn)行訪問,從而使開發(fā)者擁有改變文檔結(jié)構(gòu)、樣式、內(nèi)容的能力。

  • 從安全角度:DOM 是 HTML 經(jīng)過解析的內(nèi)部數(shù)據(jù)結(jié)構(gòu),它將 web 頁面和 js 鏈接起來,并過濾了一些不安全的內(nèi)容。

渲染器進(jìn)程內(nèi)部使用 HTML Parser 將 HTML 解析成 DOM 結(jié)構(gòu)。需要注意的是,HTML 解析器不會等待整個(gè) HTML 文檔加載完畢再去解析,而是加載多少了多少 HTML,就解析多少。

那么 HTML 字節(jié)流是如何轉(zhuǎn)換成 DOM 的呢?

其實(shí)和 V8 解析 js 類似,也是做詞法分析,通過分詞器將字節(jié)流成功成一個(gè)個(gè) token,包括 Tag token 和文本 token。HTML 解析器維護(hù)了一個(gè) token 棧結(jié)構(gòu),token 會按照對應(yīng)順序入棧出棧,然后將 token 解析成 DOM 節(jié)點(diǎn),并將 DOM 節(jié)點(diǎn)添加進(jìn) DOM 樹中。

前面提到生成 DOM 可以過濾一些不安全內(nèi)容。這主要是渲染引擎中的一個(gè)名為XSSAuditor 安全檢查模塊實(shí)現(xiàn)的。它會監(jiān)測詞法安全,在分詞器解析出 token 之后,檢查這些模塊是否引用了外部腳本,是否符合 CSP 規(guī)范,是否存在跨站點(diǎn)請求等。如果出現(xiàn)不符合規(guī)范的內(nèi)容。XSSAuditor 會對該腳本或下載任務(wù)進(jìn)行攔截。

DOM 樹在構(gòu)建過程中會創(chuàng)建 document 對象,然后以 document 為根節(jié)點(diǎn)的 DOM 樹不斷修改向其中添加新的元素。

解析 CSS

前面已經(jīng)將 HTML 解析成 DOM 樹了,但是光擁有 DOM 樹還不足以讓我們知道頁面的樣貌。因?yàn)槲覀兛隙〞轫撁嬖O(shè)置一些樣式。因此主進(jìn)程還會解析頁面中的 CSS 從而確定每個(gè) DOM 節(jié)點(diǎn)的計(jì)算樣式(computed style)。

CSS 的樣式來源主要有三個(gè):

  • 通過 link 引用的外部 CSS 文件

  • 使用

同樣,瀏覽器無法直接理解這些純文本的 CSS 樣式。所以渲染引擎在接受到 CSS 文本時(shí),會通過 CSS parser 執(zhí)行解析轉(zhuǎn)換操作。解析過程和 HTML 是部分類似的。最終將 CSS 文本轉(zhuǎn)換成瀏覽器可以理解的結(jié)構(gòu) styleSheets,這個(gè)結(jié)構(gòu)具備查詢和修改的能力,為后續(xù)的樣式操作提供基礎(chǔ)。

然后將 styleSheet 中的屬性值進(jìn)行標(biāo)準(zhǔn)化操作,比如我們在寫樣式時(shí)常常用到 font-size:1em、color:bule、font-weight:bold 等轉(zhuǎn)換成標(biāo)準(zhǔn)的計(jì)算值。

最后根據(jù)層疊樣式的繼承規(guī)則和層疊規(guī)則,計(jì)算出的每個(gè) DOM 節(jié)點(diǎn)的樣式,被保存在 ComputedStyle 結(jié)構(gòu)內(nèi)。

渲染樹 Render Tree VS 布局樹 LayoutTree

到目前為止,我們已經(jīng)在渲染器進(jìn)程的主線程中走完了前兩步。我們已經(jīng)有了節(jié)點(diǎn),又知道了節(jié)點(diǎn)的樣式,是不是就可以開始渲染了 ?

不,進(jìn)度條告訴我們事情遠(yuǎn)沒有那么簡單。

但是在進(jìn)行下一步之前,我們還需要厘清些概念。這其中 Layout Tree 我們是常聽的,那 Render Tree又是啥?它和 Layout Tree一樣嗎?

Layout Tree 不等于 Render Tree 。

從這篇開發(fā)者文檔[https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction?hl=zh-cn]中的配圖可以看到,Render tree 是將 dom 和 cssom 結(jié)合的產(chǎn)物。也就是主線程解析 CSS 并把計(jì)算后的樣式添加到 dom 節(jié)點(diǎn)上,進(jìn)而得到了一個(gè)渲染樹。

The main thread parses CSS and determines the computed style for each DOM node. This is information about what kind of style is applied to each element based on CSS selectors.

———《Inside look at modern web browser(part 3)》

如圖所示,我們只是知道了節(jié)點(diǎn)是否可見和它們的可見樣式,但是還不知道節(jié)點(diǎn)的精確位置和大小。也就是需要進(jìn)行布局。

主線程從 render tree 的根節(jié)點(diǎn)開始遍歷,按照一定規(guī)則處理后,將得到一個(gè)盒模型 。它會精確的捕獲每個(gè)元素在視口內(nèi)的確切位置和尺寸,所有的相對測量值都會轉(zhuǎn)換為屏幕上的絕對元素。在得知了那些節(jié)點(diǎn)可見,計(jì)算樣式和幾何信息后,渲染引擎就可以把 render tree 上的每個(gè)節(jié)點(diǎn)都轉(zhuǎn)換成屏幕上的像素,這一步稱為 繪制 或者 柵格化

也就是說,Layout Tree 是 Render Tree 在進(jìn)行布局計(jì)算后的結(jié)果,在 Render tree 的基礎(chǔ)上,增加了節(jié)點(diǎn)的幾何信息。

The main thread going over DOM tree with computed styles and producing layout tree ———《Inside look at modern web browser(part 3)》

圖層樹 Layer tree

真好,我們又走完一步,現(xiàn)在我們有了節(jié)點(diǎn)還有節(jié)點(diǎn)的精確位置和樣式,可不可以渲染了?

抱歉,還是不行。

這里我們要先了解一個(gè)概念,柵格化或者說光柵化(Restering)。簡單來說柵格化就是將這些節(jié)點(diǎn)信息轉(zhuǎn)化為屏幕上的像素點(diǎn)。

那么柵格化跟我們渲染有什么關(guān)系呢?因?yàn)闉g覽器使用的正是這個(gè)技術(shù)將元素繪制在屏幕上。

Chrome 以前是在可視區(qū)域內(nèi)將元素柵格化,隨著用戶滾動(dòng)頁面,不斷調(diào)整柵格化的區(qū)域,繼續(xù)柵格化并將內(nèi)容填充到缺失部分效的方式。這樣的問題是用戶快速滾動(dòng)頁面的時(shí)候,會出現(xiàn)卡頓感。

現(xiàn)在的 chrome 柵格化是采用一種合成(composting)的技術(shù),把頁面中某些部分分到一些層中,分別柵格化它們,然后在柵格化線程中合成。這樣在頁面滾動(dòng)時(shí),原材料已經(jīng)有了(已經(jīng)柵格化好的那些層),只需要將視口內(nèi)的層合成為一個(gè)新的幀就好了。

那這又跟 Layer Tree 又有啥關(guān)系呢?

前面說過目前 Chrome 使用的是將多個(gè)圖層合成為一幀的技術(shù)。Layer Tree的作用就是,分層。

為了找到那些元素應(yīng)該在哪些層里,主線程遍歷 layout tree 來創(chuàng)建 layer tree (Chrome devtools 里稱為 ‘update layer tree’)

渲染引擎并不會為每個(gè)節(jié)點(diǎn)創(chuàng)建一個(gè)圖層,如果一個(gè)節(jié)點(diǎn)沒有圖層,那么它屬于父節(jié)點(diǎn)的圖層。想要?jiǎng)?chuàng)建新圖層,節(jié)點(diǎn)需要滿足一定條件。

  • 擁有層疊上下文屬性的元素會被提成為新的一層

頁面是二維平面,但是層疊上下文會讓 HTML 元素具有三維概念。這些元素按照自身屬性的優(yōu)先級分布在垂直于這個(gè)二維平面的 Z 軸上。

明確定位屬性的元素、定義透明屬性的元素、使用 CSS 濾鏡的元素等等,都擁有層疊上下文屬性。具體參考MDN[https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context]。

  • 需要裁減的地方也會被創(chuàng)建為圖層

當(dāng)我們在一個(gè) 100100 的 div 中書寫大量文字時(shí),文字所顯示的區(qū)域肯定會超出 100100。這時(shí)候就產(chǎn)生了剪裁,渲染引擎會裁剪文字內(nèi)容的一部分用于顯示在 div 區(qū)域。出現(xiàn)這種裁剪情況的時(shí)候,渲染引擎會為文字部分單獨(dú)創(chuàng)建一個(gè)層。如果出現(xiàn)滾動(dòng)條,滾動(dòng)條也會被提升為單獨(dú)的層。只要滿足上述 2 條件任意之一,即會被提升為單獨(dú)一層。

繪制 Paint

經(jīng)歷了上述步驟,終于我們到了繪制這一步了。

繪制是其實(shí)一個(gè)大的過程,包括生成繪制記錄 Paint Records,合成器分圖塊,柵格線程光柵化(調(diào)用 GPU 生成位圖),合成器幀提交等過程。

通過分層我們知道了一些特殊元素的層級關(guān)系。但是,我們還不知道同一層內(nèi)的元素的層級關(guān)系,誰該覆蓋誰。主線程根據(jù)前面的 Layer Tree 為每一層創(chuàng)建繪制記錄表 Paint Records,決定誰先畫誰后畫。后畫上去的肯定覆蓋前面的,也就決定了同一層內(nèi)的元素層級。繪制記錄表也理解成一個(gè)類似單向鏈表的形式,遍歷鏈表即可獲得繪制順序。

在查看文檔的過程中,我們會發(fā)現(xiàn)不同文檔對先生成 Layer Tree 還是先得到 Paint Records 有不同說法。

我理解的應(yīng)該是先分層,然后對每一層創(chuàng)建 Paint Records。如果是先遍歷整個(gè) Layout tree 得到繪制記錄再分層的話,會多了很多額外的工作,比如把繪制記錄的某些繪制步驟挑出來和某些層綁定在一起。而且從 Chrome devtool 里的 profermance 可以看到,先創(chuàng)建了 layer tree,然后開始 paint。

有了圖層繪制記錄表之后,將信息提交給合成器線程進(jìn)行合成。由于一個(gè)圖層可能非常非常大,超過了視口的面積,那么一次性將這么大的圖層全繪制出來是沒有必要的。所以還需要將圖層分割成一個(gè)個(gè)圖塊 Tile, 優(yōu)先繪制這些圖塊。圖塊大小通常是256256 或 512512,然后將圖塊信息傳遞給柵格化線程池

柵格化線程池中都是柵格化線程,這些線程執(zhí)行柵格任務(wù) Raster Task 將圖塊生成位圖,優(yōu)先生成視口 viewport 附近的位圖。通常柵格化過程使用 GPU 來加速,所以又稱為快速柵格化、GPU 柵格化。

當(dāng)所有的圖塊柵格化完畢,合成器線程收集 Draw Quads 的圖塊信息。Draw Quads 記錄了圖塊在內(nèi)存中的位置和在頁面哪個(gè)位置繪制圖塊。

現(xiàn)在萬事俱備,在主線程內(nèi)將 Draw Quads 這些信息合成合成器幀 (Compositer Frame)并通過 IPC管道發(fā)送給瀏覽器進(jìn)程。瀏覽器進(jìn)程再將合成器幀發(fā)送給GPU。

GPU執(zhí)行渲染,頁面出現(xiàn)!!!

大功告成!!!但是這不是結(jié)束,我們還要考慮到重排重繪。

從線程角度看重排重繪

作為前端經(jīng)常聽到說重排比重繪的開銷大,那我們從線程角度該如何理解呢?

重排(回流)

如果通過 js 或 CSS 修改元素的幾何位置屬性,如寬度、高度等,那么瀏覽器會觸發(fā)重新布局。也就是重新生成 layout tree 及以后的所有流程,并全都再走一遍。這種開銷是比較大的。

重繪

如果只是改變元素背景顏色,則不用修改 layout tree 和 layer tree,也不用修改進(jìn)入繪制以及之后的流程。由于省略了布局和分層階段,開銷會小一些,效率較高。

直接合成

如果更改一個(gè)即不要布局也不需要繪制的屬性,則渲染引擎將跳過布局和繪制階段,只執(zhí)行后續(xù)的合成操作,我們把這個(gè)過程稱之為合成。

js 執(zhí)行,重排,重繪都是運(yùn)行在主線程的,都有可能因?yàn)榇罅康挠?jì)算導(dǎo)致頁面卡頓。而除了主線程外,還有合成器線程和柵格線程,如果能不使用主線程直接進(jìn)行合成的話,就能使頁面更加流暢。

css 3 transform 就是這樣的一個(gè)屬性,它實(shí)現(xiàn)動(dòng)畫效果可以避開重排和重繪,直接在非主線程上執(zhí)行動(dòng)畫合成的操作。由于不占用主線程,并且也沒有布局和繪制的階段,所以效率是最高的。

另外,除了使用 transform 屬性外,還可以使用 requestAnimationFrame 方法。requestAnimationFrame 傳入的 callback 會在下一幀的重繪前調(diào)用,從而盡可能的提高動(dòng)畫幀率。可以參考這篇文檔[https://zhuanlan.zhihu.com/p/64917985]。

延展閱讀

瀏覽器的演進(jìn)

按照目前發(fā)展情況來,未來 Chrome 整體架構(gòu)會朝向現(xiàn)代操作系統(tǒng)所采用的“面向服務(wù)的架構(gòu)” 方向發(fā)展,以達(dá)到簡單、穩(wěn)定、高速、安全的目標(biāo)。

現(xiàn)有的各種模塊將重構(gòu)成獨(dú)立的服務(wù)(Service),比如把 UI、數(shù)據(jù)庫、文件、設(shè)備、網(wǎng)絡(luò)等模塊重構(gòu)為類似操作系統(tǒng)底層的基礎(chǔ)服務(wù),并在各自獨(dú)立的進(jìn)程中運(yùn)行。同時(shí)通過使用定義好的接口以及 IPC 來通信、訪問,讓系統(tǒng)更內(nèi)聚、松耦合、易于維護(hù)和擴(kuò)展。

同時(shí) Chrome 還提供靈活的彈性架構(gòu),在強(qiáng)大性能設(shè)備上以多進(jìn)程的方式運(yùn)行基礎(chǔ)服務(wù),在資源受限的設(shè)備上(如下圖),則會將很多服務(wù)整合到一個(gè)進(jìn)程中,從而節(jié)省內(nèi)存占用。谷歌開發(fā)者文檔[https://developers.google.com/web/updates/2018/09/inside-browser-part1#at_the_core_of_the_computer_are_the_cpu_and_gpu]

目前 Chrome 正在逐步構(gòu)建 Chrome 基礎(chǔ)服務(wù)(Chrome Foundation Service)這將是一個(gè)漫長的迭代過程,讓我們一起拭目以待。

參考文獻(xiàn)

Render-tree Construction,Layout,and Paint:

[https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction]

Inside look at modern web browser(par1 - part4):

[https://developers.google.com/web/updates/2018/09/inside-browser-part3]

Chrome 瀏覽器架構(gòu):

[https://xie.infoq.cn/article/5d36d123bfd1c56688e125ad3]

Chrome架構(gòu):僅僅打開了1個(gè)頁面,為什么有4個(gè)進(jìn)程:

[https://blog.poetries.top/browser-working-principle/guide/part1/lesson01.html#%e8%bf%9b%e7%a8%8b%e5%92%8c%e7%ba%bf%e7%a8%8b]

requestAnimationFrame 回調(diào)時(shí)機(jī):

[https://zhuanlan.zhihu.com/p/64917985]

層疊上下文:

[https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context]

Process Models:

[https://www.chromium.org/developers/design-documents/process-models]

總結(jié)

以上是生活随笔為你收集整理的简略图解:输入 url 到出现页面,浏览器做了什么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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