「百毒不侵(二)」戲說 「瀏覽器渲染」

image.png

你們好,林三心又來了。看了十幾遍《康熙王朝》《雍正王朝》,今天,就給你們講講「九龍奪嫡」的那些事,順便講講瀏覽器渲染(實際上是講瀏覽器渲染,順便講講「九龍奪嫡」,嘿嘿),以爲講得好記得給個哦。css

畢竟,我也是一個有夢想的做者呢!html

image.png

主角介紹(模塊介紹)

請記住對應的關係哦,有利於後面更好地理解模塊之間的關係jquery

康熙(瀏覽器)

提及我們的康熙大帝啊,那可就牛逼了,擒鰲拜,平三番,遠征葛爾丹。可是也不耽誤他風流啊。「九子奪嫡」,說白了就是九個臭小子互相干架爭本身老子的皇位,那也怪不得這些臭小子啊,誰叫康熙大帝生那麼多呢?固然,九子中最突出的那幾個分別是大阿哥胤禔(HTML解析器),老三胤祉(繪圖模塊),老四胤禛(JS引擎),老八胤禩(CSS解析器),老十三(佈局Layout模塊)webpack

image.png

大阿哥(HTML解析器)

  • 性格:康熙的大兒子,身強力壯,喜歡打仗,就是沒啥腦子(打仗還被俘虜過,丟人啊)
  • 技能:只解析HTML標籤,順便解析內聯style標籤裏的樣式,構建DOM樹

八阿哥(CSS解析器)

  • 性格:康熙的八兒子,表面工做作得很漂亮(天天都在學他老爸,卻學的最不像)
  • 技能:解析link標籤裏的外聯漂亮樣式,構建CSS樹

四阿哥(JS引擎)

  • 性格:康熙的四兒子,最有腦子的兒子,是個腹黑男(後來的雍正帝)
  • 技能:暗地裏操縱各類樣式DOM節點(增刪改查或者綁定事件)

十三阿哥(佈局Layout模塊)

  • 性格:直來直去,豪爽,對各位兄弟都很仗義(這麼仗義,不適合作皇帝)
  • 技能:把DOM樹CSS樹合併,並製成一張佈局圖紙(不負責渲染,只提供圖紙)

三阿哥(繪圖模塊)

  • 性格:文人一個,好書畫,畫的一手好畫啊(滿人是馬背上的民族,能將皇位傳給你這個文人才怪)
  • 技能:接過老十三手中的圖紙,並繪製出來給大夥看

大體渲染過程

image.png

  1. 大阿哥(HTML解析器)遇到HTML標籤就解析,並構造出DOM樹
  2. 八阿哥(CSS解析器)將link標籤裏的CSS樣式解析,並構建CSS樹
  3. 大阿哥和八阿哥把各自的DOM樹和CSS樹交給四阿哥(JS引擎)
  4. 四阿哥(JS引擎)處理script裏的js代碼,並根據js代碼,完成綁定事件,修改CSS樹和DOM樹等操做
  5. 十三阿哥(佈局Layout模塊)將修改後的CSS樹和DOM樹合成一個渲染樹,並設計出佈局圖紙,交給三阿哥(繪圖模塊)
  6. 康熙(瀏覽器)請求各類圖片資源,音頻資源等等,一齊交給三阿哥
  7. 三阿哥(繪圖模塊)但是畫畫高手啊,立刻根據這張圖紙而且皇阿瑪給的素材,畫出整個頁面給大夥看

各位阿哥們之間的關係(模塊之間的關係)

看如下內容以前,你們要先明白一個道理:解析渲染是兩個過程,解析了不必定會渲染(也就是你還看不到頁面效果),渲染了說明解析完了,這就比如:你有了錢(解析)不必定會去買別墅(渲染),可是若是你買了別墅(渲染)那說明你是真的有錢(解析web

HTML解析器

<style>
     // 6萬行css樣式
     .box { background: red } // 最後一行
 </style>
 <div class="box"></div>
 <div></div>
 <div></div>
 <div></div>
複製代碼
  • 問: HTML解析器負責解析HTML標籤,順便解析內聯style標籤裏的樣式,那麼問題來了:style標籤裏有6萬多行樣式,會由於解析得太慢,而致使後面的div標籤都沒法解析而且渲染嗎?
  • 答: 不會,HTML解析器是異步解析的,而且阻塞渲染。大阿哥(HTML解析器)從上往下走,碰到了style標籤,發現裏面實在是太多樣式了,判斷須要解析好久,便派了四個小兵,先去解析下面的四個div標籤並先渲染出來,提升效率。
  • 形成的問題: 因爲style裏太多樣式,因此小兵們解析渲染div標籤完,大阿哥卻還未解析完style裏的樣式,因此class="box"的div標籤先渲染出來(無樣式),等大阿哥解析完style標籤,纔會把.box的樣式賦給這個渲染出來的div標籤,這就致使了這個div標籤在頁面上出現了無樣式 -> 有樣式的效果,也就是所謂的閃屏現象
  • 如何解決問題: 少用style內聯標籤,大阿哥要帶兵解析HTML已經夠累了,你還讓他去解析style標籤,不形成'閃屏現象'纔怪

HTML解析器和CSS解析器

// index.css裏
  // 6萬行css樣式
  .box { background: red } // 最後一行


 // html代碼
 <link href="index.css"></link> // 引入 <div class="box"></div>
 <div></div>
 <div></div>
 <div></div>
複製代碼
  • 問: CSS解析器負責解析link標籤裏的外聯樣式,那麼問題來了:link標籤外聯樣式有6萬多行,會由於解析得太慢,而致使後面的div標籤都沒法解析而且渲染嗎?
  • 答: 不會阻塞後面div標籤的解析,可是阻塞後邊div標籤的渲染,也就是說,CSS解析器在解析link標籤裏這6萬行樣式的同時,HTML解析器已經帶了幾個小兵去把下面的div標籤全解析了,但只是解析了,並未渲染出來,等到CSS解析器把6萬行樣式解析完,再一次性合併CSS樹DOM樹並渲染到頁面上去
  • 爲何: 由於這麼作能夠避免閃屏現象提升渲染性能。上面說了閃屏現象就是頁面上出現了無樣式 -> 有樣式的效果,體驗不好,因此如何避免呢?最好的辦法就是等到最終的DOM樹最終的CSS樹結合完,再一次性渲染上去,這樣頁面就不會出現無樣式 -> 有樣式這樣的問題了。屢次的渲染如今變成了一次性渲染,那天然是提升了渲染的性能。
  • 形成的問題: 若是CSS解析器解析的太慢,那麼頁面就一直沒法完成最終渲染,也就會出現一小段時間白屏現象
  • 如何解決問題: 核心就是加快外聯樣式的加載速度:
  1. 使用CDN節點進行外部資源加速
  2. 對外部樣式文件進行壓縮(使用打包工具,例如webpack,gulp等)
  3. 優化你的樣式文件的代碼

HTML解析器和JS引擎

// index.js文件
  // 6萬多行代碼,對dom進行了一系列操做

// html頁面
 <script src="index.js"></script> // 引入 <div id="box"></div>
 <div></div>
 <div></div>
 <div></div>
複製代碼
  • 問: JS引擎暗地裏操縱各類樣式DOM節點(增刪改查或者綁定事件),會由於執行script標籤的引用代碼太慢,而致使後面的div標籤都沒法解析而且渲染嗎?
  • 答: 阻塞後面div標籤的解析和渲染,等到JS引擎把全部JS代碼加載執行完成,纔會放HTML解析器往下解析DOM,而且一次性渲染出來
  • 爲何: 舉個反例,在四阿哥(JS引擎)緩慢地執行這6萬行代碼同時,康熙命令大阿哥(HTML解析器)不要管四阿哥,大膽地往下解析HTML,大阿哥立刻帶着本身的小兵們立刻解析完全部div標籤,而後滿懷成就感地想跑去康熙面前請功領賞,而此時四阿哥還未執行完他的JS代碼,大阿哥跑啊跑啊,跑到康熙面前的一瞬間,四阿哥恰好執行完JS代碼,並把大阿哥剛剛解析完的全部標籤都刪了(畢竟四阿哥擁有操控DOM的能力啊),康熙一看,雷霆大怒:「WDNMD!!!老大,你不是說都解析好了嗎?在哪呢??敢騙老子?」對着大阿哥一頓臭罵。大阿哥心想:「老四,WDNMD,敢把老子解析的成功給刪了!」後來康熙得知後,便制定了一套規則:之後四阿哥先執行代碼,而後再派大阿哥去解析HTML,這樣大阿哥就不會作無用功啦!
  • 問題: 若是JS代碼執行報錯或者執行過慢,那麼後面的HTML就會永遠沒法解析了,那麼頁面有可能就一直是一片空白。
  • 如何解決問題: 核心就是改變JS代碼的執行順序,或者優化JS執行速度:
  1. <script async></script> 加上async屬性,JS代碼會異步加載並執行(多script標籤狀況下,並不會按着script在頁面中的順序來執行,而是誰先加載完誰執行)
  2. <script defer></script> 加上defer屬性,JS代碼會異步加載(若是有多個設置了defer的script標籤存在,則會按照順序執行全部的script,會在DOMCotentLoaded前執行)
  3. 把script標籤放在頁面尾部
  4. 優化JS代碼,加快執行速度

CSS解析器和JS引擎

跟上面HTML解析器和JS引擎同理,只不過是DOM樹CSS樹的區別gulp

JS引擎和JS引擎

<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
複製代碼

會先執行完上邊script再執行下邊script,由於有可能下邊的script依賴於上邊的script代碼(上方例子,bootstrap依賴於jquery)bootstrap

<script src="index1.js"></script>
<script src="index2.js"></script>
<div></div>
複製代碼

會先執行完上邊script再執行下邊script,由於上方script可能修改dom,下方也修改dom,那確定是排隊一個一個來,否則就亂套了瀏覽器

<script src="index1.js" defer></script>
<script src="index2.js" defer></script>
複製代碼

會異步加載,也就是下方可能比上方加載更快,可是最終代碼執行仍是會按順序由上往下,而且在DOMContentLoaded以前執行markdown

<script src="index1.js" async></script>
<script src="index2.js" async></script>
複製代碼

會異步加載並異步執行,也就是誰先加載完誰就先執行,不按順序app

一點點疑問

問:爲何CSS解析器只能阻塞HTML渲染但不能阻塞HTML解析,但JS引擎卻能同時阻塞HTML的解析和渲染呢?

答:由於CSS並不能操做DOM啊,因此也不必阻塞HTML解析。可是JS引擎就不同了,能隨意操做DOM,因此須要阻塞HTML解析,避免HTML解析器作無用功。

DOMContentLoaded和onload

再來看看渲染大體過程:

  1. 大阿哥(HTML解析器)遇到HTML標籤就解析,並構造出DOM樹
  2. 八阿哥(CSS解析器)將link標籤裏的CSS樣式解析,並構建CSS樹
  3. 大阿哥和八阿哥把各自的DOM樹和CSS樹交給四阿哥(JS引擎)// DOMContentLoaded發生在這
  4. 四阿哥(JS引擎)處理script裏的js代碼,並根據js代碼,完成綁定事件,修改CSS樹和DOM樹等操做
  5. 十三阿哥(佈局Layout模塊)將修改後的CSS樹和DOM樹合成一個渲染樹,並設計出佈局圖紙,交給三阿哥(繪圖模塊)
  6. 康熙(瀏覽器)請求各類圖片資源,音頻資源等等,一齊交給三阿哥
  7. 三阿哥(繪圖模塊)但是畫畫高手啊,立刻根據這張圖紙而且皇阿瑪給的素材,畫出整個頁面給大夥看 // onload發生在這

結語

JavaScript是瀏覽器中運行的大腦,最能獲得瀏覽器(康熙)青睞的確定是JavaScript(四阿哥),因此最後確定是四阿哥胤禛勝出啦,恭喜雍正帝

雍正也是我很喜歡的一位,推行新政火耗歸公攤丁入畝士紳一體當差一體納糧派年羹堯平定羅布贊旦增阿拉布坦叛亂等等,都很出色!

感興趣的能夠去看看《雍正王朝》,和《大明王朝》並列爲中國古裝劇的巔峯之做!

相關文章
相關標籤/搜索