原文連接:Tags to DOM
原文做者:Travis Leithead
譯者:wangds
javascript
這是一個系列文章,分爲四個部分介紹了從輸入URL到頁面呈現的詳細過程css
本篇翻譯的是第二部分:Tags to DOMhtml
在上一篇文章中(客戶端從服務器獲取資源),咱們談論了資源是如何從服務器到達客戶端的,同時也闡述了一些關於緩存、同源的概念。本篇文章將聊一聊HTML
資源是如何轉化成DOM tree
的。java
當瀏覽器得到了資源之後要進行的第一步工做就是解析,整個解析的過程能夠拆分紅以下四個步驟:web
encoding
)pre-parsing
)Tokenization
)tree construction
)encoding
)客戶端接收的內容能夠是HTML
文本、圖像等等任何格式的數據。在從服務器到客戶端展現的過程當中,數據通過了以下的過程:canvas
bit
bit
進行數據傳輸bit
轉化成數據因此客戶端必須知道數據轉化成bit
的格式,以便客戶端將bit
反轉成正確的數據。瀏覽器
咱們以HTML
舉例來講,HTML
的文本格式有不少種,因此服務器在返回數據的時候在響應頭中使用Content-Type
告知瀏覽器文本的內容類型,同時在文本文件頭部使用Byte Order Mark
告知瀏覽器編碼格式。若是瀏覽器仍然判斷不了解碼方式,瀏覽器還會自行匹配一種解碼格式來處理數據。有時候,解碼格式也會寫在<meta>
標籤中。這就致使會出現一種奇葩的現象,瀏覽器先是以本身的方式去解碼文本,而後遇到了標明解碼方式的<meta>
標籤。這時候瀏覽器就會從新解析按照<meta>
標籤進行解析。緩存
咱們如今常常在HTML
中使用的文件格式是UTF-8
,那是由於UTF-8
能較完整的支持Unicode
字符範圍,同時與CSS
、JavaScript
中常見的節字符具備良好的ASCII
兼容性。通常瀏覽器默認的解碼格式也是 UTF-8
。當解碼出錯的時候,咱們會看到屏幕上所有都是亂碼字符。bash
完成了解碼之後,瀏覽器會開啓一個預解析的過程,「偷偷獲取」後面須要加載的資源,減小處理的時間。預解析的過程不是一個完整的解析過程。舉例來講,預解析不會處理HTML
內元素之間嵌套的父子層級。可是預解析仍是能識別一些特殊的HTML
標籤、元素屬性值以及URL
。假如咱們的頁面中有個img
(以下),預解析就會注意src
屬性值,並將獲取這個圖片的請求加到請求隊列中,儘早的將圖片獲取到本地以便顯示。咱們也能夠經過prefetch
和preload
兩種屬性將須要儘早加載的資源告知於瀏覽器。服務器
<img src="https://somewhere.example.com/images/dog.png" alt="">
複製代碼
符號化是將輸入解析成爲符號,像開始標籤(<
)、結束標籤(>
)、註釋(//
)、文本內容等等。而後這些符號將被送到解析的下一個步驟。完成符號化工做的機器叫作符號識別器( tokenizer
),符號識別器是一種狀態機。 咱們以<video controls>
的標籤爲例:
Data State
,<
的時候,狀態變成Tag open state
Tag name state
in attribute name state
after attribute name state
>
的時候,狀態變成Data state
從解析<video controls>
標籤咱們就能夠知道,整個頁面會碰到不少標籤,符號識別器就會不斷的重複狀態變化。(下圖中的箭頭就是狀態機處於的某個位置)
HTML標準
目前爲符號識別器定義了80個獨立的狀態。在解析的過程當中,符號識別器能夠將任何的文本轉化成HTML
文檔(即使文本內容不是有效的HTML
)。這種彈性的機制使得HTML
更加的易於開發,可是也可能致使由於寫錯標籤出現特殊的bug。
對於那些更喜歡使用‘非黑即白’驗證規則的人,瀏覽器內置了一種替代解析機制,可將任何解析錯誤視爲災難性的故障(出現錯誤就會致使沒法呈現內容)。 這種解析模式使用XML
規則來處理HTML
,咱們能夠經過設置MIME
類型的值爲application / xhtml + xml
開啓這種解析模式。
瀏覽器能夠同時處理預解析和標記化兩個過程(也就是說這是兩個線程)。
tree construction
)在上一步符號化之後,解析器得到這些符號標記,而後以合適的方法建立DOM
對象並將這些符號插入到DOM
對象中。DOM
對象的數據結構是樹狀的,因此這個過程稱爲構造樹(tree construction
)。順便說一句,在IE
的歷史中,大部分時間裏沒有使用樹結構。
另外現代瀏覽器爲了兼容舊版本HTML
,解析的過程仍是十分複雜的。例如瀏覽器能夠自動閉合標籤。
<p>sincerely<p>The authors</p> //HTML的樣子
<p>sincerely</p><p>The authors</p>//瀏覽器解析出來的樣子
複製代碼
咱們可使用JavaScript
去任意修改DOM
。假如咱們用JavaScript
進行無心義的操做(例如在video
元素內插入一個table
單元格),渲染引擎能夠甄別出這些操做不合規,也不進行渲染(可是這個過程渲染引擎也進行工做只是不展現)。
由於JavaScript
能夠在DOM
中添加內容。因此遇到JavaScript
文件的時候,DOM
將中止解析;若是JavaScript
文件內調用了document.write
API,解析器將從新開始解析過程。
當整個解析的過程完成之後,瀏覽器會經過DOMContentLoaded
事件來通知DOM
解析完成。事件至關於一套廣播系統用來通知和監聽瀏覽器。除了DOMContentLoaded
事件,還有load
事件(表示全部資源已經加載完成,包括圖片、視頻、CSS
等等)、unload
事件表示界面即將關閉、鼠標事件鍵盤事件等等。
瀏覽器在DOM
對象中還會建立一個事件對象,該對象包含大量有用的信息(如屏幕中的座標、按下的按鍵等等)。當JavaScript
觸發事件的時候,就會同時產生事件對象。
在目標元素上觸發事件的時候,須要從DOM
樹的根元素開始向子元素查找,這個過程俗稱事件捕捉階段。到達目標元素之後,還要逐級向上返回到根元素上,這個過程俗稱事件冒泡階段。
事件是能夠進行關閉的,咱們能夠在事件捕獲或者傳播的過程當中選擇關閉,例如在form
的提交過程當中判斷字符串爲空則關閉提交。
解析器解析出來的元素能夠包含一些基本的交互功能(<video>
能播放視頻、<button>
按鈕等),可是這些基本的交互功能還不能知足咱們的需求,咱們須要使用css
和JavaScript
將頁面展現的更加豐富多彩,而DOM
就是HTML
元素與其餘資源交互的橋樑。
元素的接口
在解析器將元素放入DOM
樹以前,解析器會根據不一樣元素的名稱賦予元素不一樣的接口功能。
下面是一些通用的功能:
DOM
中像<table>
元素具備查找刪除表內全部單元格的能力;<canvas>
具備描繪線條、圖形的能力。可是想要調用這個接口仍是須要JavaScript
來操做。
每當咱們使用JavaScript
操做DOM
的時候,將會觸發瀏覽器的一些連鎖反應,這些反應是爲了讓更改後的頁面更快的呈如今屏幕上。例如:
sub-tree
的跟蹤變化降到最低,避免‘污染’整個DOM
樹DOM
中的HTML
元素是頁面展現的基礎,DOM
的能力也不只僅侷限於上面咱們提到的功能。其餘諸如訪問儲存系統(瀏覽器中的緩存)、設備功能(藍牙、定位)、以及3D圖形繪製等等功能。隨着瀏覽器的不斷進步和web標準的不斷實施,DOM
的功能只會愈來愈強大,本文只涉及了一部分而已。
以上就包含了標籤轉化成DOM的過程。下一篇文章咱們將聊聊CSS解析的過程。
限於本人水平有限,文中若有錯誤感謝您指正。