HTML執行順序一探究竟


了解瀏覽器線程基礎

一個頁面的呈現主要是由瀏覽器渲染進程實現的(render進程),主要作用為頁面的渲染,腳本執行,事件處理等。而render進程是多線程的,它主要包含以下主要線程:

1 GUI渲染線程

  • 負責渲染瀏覽器界面,解析HTML,CSS,構建DOM樹和RenderObject樹,布局和繪制等。
  • 當界面需要重繪(Repaint)或由於某種操作引發回流(reflow)時,該線程就會執行
  • 注意,GUI渲染線程與JS引擎線程是互斥的,當JS引擎執行時GUI線程會被掛起(相當於被凍 結了),GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執行。

2 JS引擎線程

  • 也稱為JS內核,負責處理Javascript腳本程序。(例如V8引擎)
  • JS引擎線程負責解析Javascript腳本,運行代碼。
  • JS引擎一直等待着任務隊列中任務的到來,然后加以處理,一個Tab頁(renderer進程)中 無論什么時候都只有一個JS線程在運行JS程序
  • 同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。

3 事件觸發線程

  • 歸屬於瀏覽器而不是JS引擎,用來控制事件循環(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協助)
  • 當JS引擎執行代碼塊如setTimeOut時(也可來自瀏覽器內核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應任務添加到事件線程中
  • 當對應的事件符合觸發條件被觸發時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理
  • 注意,由於JS的單線程關系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執行)

4 定時觸發器線程

  • 傳說中的setInterval與setTimeout所在線程
  • 瀏覽器定時計數器並不是由JavaScript引擎計數的,(因為JavaScript引擎是單線程的, 如果處於阻塞線程狀態就會影響記計時的准確)
  • 因此通過單獨線程來計時並觸發定時(計時完畢后,添加到事件隊列中,等待JS引擎空閑后執行)

5 異步http請求線程

  • 在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求
  • 將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件隊列中。再由JavaScript引擎執行。

JS阻塞特性

由上述GUI線程和JS引擎互斥的關系,我們也就能更好的理解為什么JS運行會阻塞頁面的渲染,也就是常說的JS阻塞特性

HTML整體執行步驟

0.加載整體html文件

1.至上而下解析html

2.解析html建立dom樹,遇到諸如<script>、<link>等標簽時,就會去下載相應內容,並解 
析、執行。如果是<link>標簽,解析css構建CSSOM樹

4.DOM和CSSOM結合生成render樹

5.布局render樹(Layout/reflow),負責各元素尺寸、位置的計算

6.繪制render樹(paint),繪制頁面像素信息

7.瀏覽器會將各層的信息發送給GPU,GPU會將各層合成(composite),顯示在屏幕上。

HTML解析過程是至上而下的,當html解析器遇到諸如<script>、<link>等標簽時,就會去下載相應內容。且加載、解析、執行JavaScript會阻止解析器往下執行,要強調 渲染 和 下載是不沖突的,渲染是GUI線程在執行,下載是下載線程在執行,瀏覽器多線程。

DOM文檔加載步驟: 

1.解析HTML結構 
2.加載外部的腳本和樣式文件 
3.解析並執行腳本代碼 
4.執行$(function(){})內對應代碼 
5.加載圖片等二進制資源 
6.頁面加載完畢,執行window.onload

①html:貫穿整個頁面

②css:三種聲明方式

  • 外聯樣式表:在head便簽中 用link標簽的href屬性來引用后綴名為.css的css樣式文件
  • 內聯樣式表:在head標簽下的style標簽中,選擇器 + 樣式聲明
  • 內部樣式表:在標簽的style屬性中添加css樣式聲明

③JavaScript:在<script>標簽中,可以在head標簽中,也可以在body標簽中(區別一會再說)

寫的位置:

  • html貫穿整個頁面,
  • css可以定義在head頭標簽中,也可以在定義在html標簽的屬性中
  • JavaScript定義在<script>標簽中,<script>標簽既能在head標簽中定義也能在body標簽中定義

加載順序:

從上到下運行,先解析head標簽中的代碼,

(1)head標簽中會包含一些引用外部文件的代碼,從開始運行就會下載這些被引用的外部文件

當遇到script標簽的時候,瀏覽器暫停解析(不是暫停下載),將控制權交給JavaScript引擎(解釋器)
如果<script>標簽引用了外部腳本,就下載該腳本,否則就直接執行,執行完畢后將控制權交給瀏覽器渲染引擎

(2)當head中代碼解析完畢,會開始解析body中的代碼

如果此時head中引用的外部文件沒有下載完,將會繼續下載
瀏覽器解析body代碼中的元素,會按照head中聲明一部分樣式去解析
如果此時遇到body標簽中的<script>,同樣會將控制權交給JavaScript引擎來解析JavaScript
解析完畢后將控制權交還給瀏覽器渲染引擎。
當body中的代碼全部執行完畢、並且整個頁面的css樣式加載完畢后,css會重新渲染整個頁面的html元素。

(3)按照之前的描述,<script>寫到body標簽內靠后比較好,

因為JavaScript 會操作html元素,如果在body加載完之前寫JavaScript,會造成JavaScript找不到頁面元素
但是我們經常將<script>寫到head中,body中不會有大量的js代碼,body中的html代碼結構會比較清晰
  • window.onload: 等待頁面中的所有內容加載完畢之后才會執行
  • $(document).ready(): 頁面中所有DOM結構繪制完畢之后就能夠執行

js在頁面裝載時執行的順序就是其引入標記<script />的出現順序,<script />標記里面的或者通過src引入的外部JS,都是按照其語句出現的順序執行,而且執行過程是文檔裝載的一部分。只有全部js腳本按順序加載完畢后才開始html標簽內容的加載過程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM