1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        渲染樹的形成原理你真的很懂嗎?

        共 4809字,需瀏覽 10分鐘

         ·

        2020-08-18 08:39

        瀏覽器系列文章

        說一下為什么寫這個(gè)系列?

        • 原因一:該文章系列不管你是前端開發(fā)者,還是后端開發(fā)者在面試中經(jīng)常會(huì)被問到一個(gè)問題?“從瀏覽器輸入url到頁面顯示經(jīng)歷了哪些?”?一個(gè)?非常常見的問題,看了該系列絕對(duì)能驚到面試官,可能就因?yàn)檫@一道面試題就收了你呢!嘿嘿。

        • 原因二:自己主要是后端方向,該系列文章也是為了學(xué)習(xí)記錄,方便以后查閱。極客時(shí)間李兵老師也開了這個(gè)專欄,看后還有幾個(gè)疑問的點(diǎn),自己查詢資料學(xué)習(xí)整理一遍。

        什么是DOM

        DOM是Document Object Model(文檔對(duì)象模型)的縮寫

        W3C 文檔對(duì)象模型 (DOM) 是中立于平臺(tái)和語言的接口,它允許程序和腳本動(dòng)態(tài)地訪問和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式。-這是W3Cschool給的概念

        看了上面的概念好像太“官方”,解釋就是 DOM 是對(duì) HTML 文檔結(jié)構(gòu)化的表述,后端服務(wù)器返回給瀏覽器渲染引擎的 HTML 文件字節(jié)流是無法直接被瀏覽器渲染引擎理解的,要轉(zhuǎn)化為渲染器引擎可以理解的內(nèi)部結(jié)構(gòu),這個(gè)結(jié)構(gòu)就是 DOM。W3C 那個(gè)概念我好像還沒有把它全部翻譯完,“允許程序和腳本動(dòng)態(tài)地訪問和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式”。這里其實(shí)就是DOM的作用了

        1. 頁面展示: DOM 是生成頁面的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

        2. JavaScript 腳本操作: DOM 提供給 JavaScript 腳本操作的接口,JavaScript 可以通過這些接口對(duì) DOM 結(jié)構(gòu)進(jìn)行訪問,從而改變文檔的結(jié)構(gòu)和樣式

        3. 安全: DOM 是一道安全防線,DOM 解析階段會(huì)過濾掉一些不安全的 DOM 內(nèi)容。

        本文我主要以 Webkit 渲染引擎來講解,Safari 和 Chrome 都使用 Webkit。Webkit 是一款開源渲染引擎,它本來是為 linux 平臺(tái)研發(fā)的,后來由 Apple 移植到 Mac 及 Windows 上。

        渲染樹最終形成經(jīng)歷了哪些

        先看一張整體的流程圖

        下面圍繞這張圖和不同代表性對(duì)例子進(jìn)行講解。

        HTML解析器

        從后端返回給瀏覽器渲染引擎 HTML 文件字節(jié)流, 第一步要經(jīng)過的就是渲染引擎中的 HTML 解析器。它實(shí)現(xiàn)了將 HTML 字節(jié)流轉(zhuǎn)換為 DOM樹 結(jié)構(gòu)。HTML 文件字節(jié)流返回的過程中 HTML 解析器就一直在解析,邊加載邊解析哦(這里注意下,有些文章寫的有問題)。

        例子1:最簡單的不帶 CSS 和 JavaScript 的 HTML 代碼講解 HTML 解析器

        1. 程序員成長指北

        根據(jù)這段代碼具體分析 HTML 解析器做了哪些事

        階段一 字節(jié)流轉(zhuǎn)換為字符并W3C標(biāo)準(zhǔn)令牌化

        讀取 HTML 的原始字節(jié)流,并根據(jù)文件的指定編碼(例如 UTF-8)將它們轉(zhuǎn)換成各個(gè)字符。并將字符串轉(zhuǎn)換成 W3C HTML5 標(biāo)準(zhǔn)規(guī)定的各種令牌,例如,“”、“”,以及其他尖括號(hào)內(nèi)的字符串。每個(gè)令牌都具有特殊含義和一組規(guī)則。

        一堆字節(jié)流 bytes

        1. 3C 62 6F ...

        轉(zhuǎn)成正常的html文件

        1. koala

        2. 程序員成長指北

      2. 階段二 通過分詞器將字節(jié)流轉(zhuǎn)化為 Token

        分詞器將字節(jié)流轉(zhuǎn)換為一個(gè)一個(gè)的 Token,Token 分為 Tag Token和文本 Token,上面這段代碼最后分詞器轉(zhuǎn)化后的結(jié)果是:

        階段三和階段四 將 Token 解析為 DOM 節(jié)點(diǎn),并將 DOM 節(jié)點(diǎn)添加到 DOM 樹中

        HTML 解析器維護(hù)了一個(gè) Token 棧結(jié)構(gòu)(數(shù)據(jù)結(jié)構(gòu)真是個(gè)好東西),這個(gè)棧結(jié)構(gòu)的目的就是用來計(jì)算節(jié)點(diǎn)間的父子關(guān)系,在上一個(gè)階段生成的 Token 會(huì)被順序壓到這個(gè)棧中,以下是具體規(guī)則:

        • HTML 解析器開始工作時(shí),會(huì)默認(rèn)創(chuàng)建了一個(gè)根為 document 的空 DOM 結(jié)構(gòu),同時(shí)會(huì)將一個(gè) StartTag document 的 Token 壓入棧底。

        • 如果壓入到棧中的 StartTagToken,HTML 解析器會(huì)為該 Token 創(chuàng)建一個(gè) DOM節(jié)點(diǎn),然后將這個(gè) Dom節(jié)點(diǎn)加入到 DOM樹中,它的?父節(jié)點(diǎn)就是棧中相鄰的那個(gè)元素生成的 DOM節(jié)點(diǎn)

        • 如果分詞器解析出來的是文本 Token,那么會(huì)生成一個(gè)文本節(jié)點(diǎn),然后把這個(gè)文本 Dom 節(jié)點(diǎn)加入到 DOM 樹中(注:文本Token不需入棧),它的?父節(jié)點(diǎn)就是當(dāng)前棧頂 Token 所對(duì)應(yīng)的 DOM 節(jié)點(diǎn)。

        • 如果分詞器解析出來的是 EndTag 標(biāo)簽,比如例子中的 EndTag div,HTML 解析器會(huì)查看 Token棧頂?shù)脑厥欠袷?StartTag div,如果是,就將 StartTag div從棧中彈出,邊上該 div 元素解析完成。

        • 最后按照上面的規(guī)則,分詞器一路解析下來,就形成了這個(gè)簡單的 DOM 樹。

        此時(shí)應(yīng)該搞懂了核心圖中 HTML 解析器的部分,和 DOM 樹的基本繪制流程,但是現(xiàn)實(shí)很殘酷,哪里有這么簡單的前端代碼,還有有 JavaScript 和 CSS 呢!繼續(xù)往下看

        CSS解析器

        CSS 解析器最終的目的也是構(gòu)建樹不過它構(gòu)建的樹是 CSSOM 樹 樹的構(gòu)建流程和 DOM 樹的構(gòu)建流程基本相同

        還是那張圖,具體我就不一一講解一遍了。直接用這個(gè)簡單例子

        1. body { font-size: 16px }

        2. div { font-weight: bold }

        3. div p { display: none }

        看下最后構(gòu)造的 CSSOM 樹

        CSSOM 為何具有樹結(jié)構(gòu)?為頁面上的任何對(duì)象計(jì)算最后一組樣式時(shí),瀏覽器都會(huì)先從適用于該節(jié)點(diǎn)的最通用規(guī)則開始(例如,如果該節(jié)點(diǎn)是 body 元素的子項(xiàng),則應(yīng)用所有 body 樣式),然后通過應(yīng)用更具體的規(guī)則(即規(guī)則“向下級(jí)聯(lián)”)以遞歸方式優(yōu)化計(jì)算的樣式。

        以上面的 CSSOM 樹為例進(jìn)行更具體的闡述。span 標(biāo)記內(nèi)包含的任何置于 body 元素內(nèi)的文本都將具有 16 像素字號(hào),并且顏色為紅色 — font-size 指令從 body 向下級(jí)聯(lián)至 span。不過,如果某個(gè) span 標(biāo)記是某個(gè)段落 (p) 標(biāo)記的子項(xiàng),則其內(nèi)容將不會(huì)顯示。

        注意點(diǎn):

        1. CSS解析可以與DOM解析同進(jìn)行

        2. 如果只有 CSS 和 HTML 的頁面,CSS 不會(huì)影響 DOM 樹的創(chuàng)建,但是如果頁面中還有 JavaScript,結(jié)論就不一樣了,請(qǐng)繼續(xù)往下看。

        javascript對(duì)DOM樹與CSSOM樹創(chuàng)建的影響

        上面兩個(gè)例子中都還沒有javascript的出現(xiàn),接下來說下JavaScript 對(duì) DOM 樹和 CSSOM 樹構(gòu)建的影響。

        • 情況1當(dāng)前頁面中只有 Html 和 JavaScript,而且 JavaScript 非外部引入

        ? ? ? ? ?DOM 樹構(gòu)建時(shí)當(dāng)遇到JavaScript腳本,就要暫停 DOM 解析,先去執(zhí)行? ? ? ? ? ? ? ? ?Javascript,因?yàn)樵贘avaScript可能會(huì)操作當(dāng)前已經(jīng)生成的DOM節(jié)點(diǎn)。

        ? ? ? ? ?有一點(diǎn)需要注意:javascript是可能操作當(dāng)前已經(jīng)生成的DOM節(jié)點(diǎn),如果是后? ? ? ? ? ?面還未生成的DOM節(jié)點(diǎn)是不生效的,比如這段代碼:

           <html>        <body>            <div>1div>            <script>                let div1 = document.getElementsByTagName('div')[0]                div1.innerText = '程序員成長指北'
        let div2 = document.getElementsByTagName('div')[1] div2.innerText = 'kaola'script> <div>testdiv> body> html>

        ? ? ? 顯示結(jié)果為兩行:

        ? ? ? 第一行結(jié)果是程序員成長指北 ? ? ? 第二行記過是test ? ? ? 因?yàn)樵趫?zhí)行第三行和第四行 script 腳本的時(shí)候,DOM樹中還沒有生成第二個(gè)? ? ? ? ? div對(duì)應(yīng)的dom節(jié)點(diǎn)。

        • 情況2:當(dāng)頁面中同時(shí)有Html JavaScript CSS ,而且都非外部引入

          DOM 樹構(gòu)建時(shí)當(dāng)遇到 JavaScript 腳本,就要暫停 DOM 解析,先去執(zhí)行 JavaScript,同時(shí) JavaScript 還要判斷 CSSOM 是否解析完成,因?yàn)樵?JavaScript 可能會(huì)操作 CSSOM 節(jié)點(diǎn),CSSOM 節(jié)點(diǎn)確認(rèn)解析完成,執(zhí)行 JavaScript 再次回到 DOM 樹創(chuàng)建。(所以這里也可以理解為CSS解析間接影響DOM樹創(chuàng)建)

        • 情況3:當(dāng)頁面中同時(shí)有Html,JavaScript, CSS ,而且外部引入

          Webkit渲染引擎有一個(gè)優(yōu)化,當(dāng)渲染進(jìn)程接收HTML文件字節(jié)流時(shí),會(huì)先開啟一個(gè)預(yù)解析線程,如果遇到 JavaScript 文件或者 CSS 文件,那么預(yù)解析線程會(huì)提前下載這些數(shù)據(jù)。當(dāng)渲染進(jìn)程接收 HTML 文件字節(jié)流時(shí),會(huì)先開啟一個(gè)預(yù)解析線程,如果遇到 JavaScript 文件或者 CSS 文件,那么預(yù)解析線程會(huì)提前下載這些數(shù)據(jù)。DOM樹在創(chuàng)建過程中如果遇到JavaScript文件,接下來就和情況2類型一樣了。

        影響關(guān)系圖: 畫了一張影響關(guān)系圖希望大家更好的記憶:

        構(gòu)建渲染樹

        通過 DOM 樹和 CSSOM 樹,瀏覽器就可以通過二者構(gòu)建渲染樹了。瀏覽器會(huì)先從 DOM 樹的根節(jié)點(diǎn)開始遍歷每個(gè)可見節(jié)點(diǎn),然后對(duì)每個(gè)可見節(jié)點(diǎn)找到適配的CSS樣式規(guī)則并應(yīng)用。具體的規(guī)則有以下幾點(diǎn)需要注意:

        • Render Tree和DOM Tree不完全對(duì)應(yīng)。

        • 請(qǐng)注意 visibility: hidden 與 display: none 是不一樣的。前者隱藏元素,但元素仍占據(jù)著布局空間(即將其渲染成一個(gè)空框),而后者 (display: none) 將元素從渲染樹中完全移除,元素既不可見,也不是布局的組成部分


        看一下前文中提到的 DOM 樹和 CSSOM 樹最終合成的渲染樹結(jié)果是:

        本文渲染樹形成過程可以做哪些優(yōu)化

        看完了渲染樹的形成,在開發(fā)過程中我們能做哪些優(yōu)化?(注意這里的優(yōu)化只是針對(duì)渲染樹形成部分,其他的優(yōu)化會(huì)在系列文章之后繼續(xù)講)

        1. 在引入順序上,CSS 資源先于 JavaScript 資源。樣式文件應(yīng)當(dāng)在 head 標(biāo)簽中,而腳本文件在 body 結(jié)束前,這樣可以防止阻塞的方式。

        2. 盡量減少在 JavaScript 中進(jìn)行DOM操作。

        3. 簡化并優(yōu)化CSS選擇器,盡量將嵌套層減少到最小。

        總結(jié)

        看完這篇文章趕緊檢測(cè)一下你寫的前端代碼,腦補(bǔ)一下渲染樹形成過程,想想自己代碼有沒有需要改善的地方,系列文章會(huì)繼續(xù)分享,下篇該系列文章渲染樹的布局與繪制以及虛擬DOM樹出現(xiàn)的必要性,感謝觀看。

        參考文章

        極客時(shí)間瀏覽器專欄 瀏覽器渲染原理 https://srtian96.gitee.io/blog/2018/06/01/瀏覽器渲染原理/

        深入理解Node.js 進(jìn)程與線程(8000長文徹底搞懂)

        [源碼解讀]一文徹底搞懂Events模塊

        Node.js 高級(jí)進(jìn)階之 fs 文件模塊學(xué)習(xí)

        Node進(jìn)階-探究不在V8堆內(nèi)存中存儲(chǔ)的Buffer對(duì)象

        說Node.js做后端開發(fā),stream有必要了解下

        require時(shí),exports和module.exports的區(qū)別你真的懂嗎?

        來,告訴你Node.js究竟是什么?

        —————END—————



        喜歡本文的朋友,歡迎關(guān)注公眾號(hào)?達(dá)達(dá)前端,收看更多精彩內(nèi)容



        點(diǎn)個(gè)[在看],是對(duì)達(dá)達(dá)最大的支持!
        瀏覽 58
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久久久久久草 | 91麻豆视频免费 | 免费看黄 片,在线观看 | 俺也去视频在线 | 吃奶爱爱视频 | 天天日天天操比 | 欧美又粗又大一区二区在线观看 | 亚洲精品手机在线 | 婷婷五月天在线观看 | 在线日本中文字幕 |