之前或多或少看過幾位比較牛逼的工程師寫過瀏覽器工做原理的分析文章,雖然很好很強大的樣子,可是看完總以爲本身對瀏覽器工做原理沒有一個全局的度,老是欠缺了好多;html
耐不住寂寞啊,就跑去堅果看過去收藏的一篇舊文,一篇冗長的,長達數萬字的文章,而後..........而後就把邊看邊給本身作一個摘要,之後須要那部分的知識就看哪裏。文章部份內容爲我斷章取義和本身標註部分理解,原文在這裏 算法
瀏覽器主要組件:後端
用戶界面 、 瀏覽器引擎 、 呈現引擎 、 網絡 、 用戶界面後端 、JavaScript 解釋器、 數據存儲 瀏覽器
解析html->dom樹->繪製dom樹結構(這期間附加style rules)->佈局dom數據(reflow)->瀏覽器中繪製->呈現網絡
經過解析器和詞法分析器組合(其中格局各類規則、詞彙、語法構建解析樹,各類云云) 併發
(根據標記化算法生成html標記dom
初始狀態是數據狀態。遇到字符 <
時,狀態更改成「標記打開狀態」。接收一個 a-z 字符會建立「起始標記」,狀態更改成「標記名稱狀態」。這個狀態會一直保持到接收 > 字符。在此期間接收的每一個字符都會附加到新的標記名稱上。在本例中,咱們建立的標記是 html 標記。異步
遇到 > 標記時,會發送當前的標記,狀態改回「數據狀態」。<body>
標記也會進行一樣的處理。目前 html 和 body 標記均已發出。如今咱們回到「數據狀態」。接收到 Hello world 中的 H 字符時,將建立併發送字符標記,直到接收 </body>
中的 <
。咱們將爲 Hello world 中的每一個字符都發送一個字符標記。佈局
如今咱們回到「標記打開狀態」。接收下一個輸入字符 /
時,會建立 end tag token 並改成「標記名稱狀態」。咱們會再次保持這個狀態,直到接收 >
。而後將發送新的標記,並回到「數據狀態」。</html>
輸入也會進行一樣的處理。優化
構建dom樹流程:
initial mode->before html(建立一個 HTMLHtmlElement 元素,並將其附加到 Document 根對象上) -> before head(沒有「head」標記,系統也會隱式建立一個 HTMLHeadElement,並將其添加到樹中)->in head(構建head內的標籤)->after head(建立並插入 HTMLBodyElement,插入document中)->in body(構建body內的標籤,知道接受</body>結束並觸發下一模式)->after body(接收 HTML 結束標記)->after after body(解析結束)。
在此階段,瀏覽器會將文檔標註爲交互狀態,並開始解析那些處於「deferred」模式的腳本,也就是那些應在文檔解析完成後才執行的腳本。而後,文檔狀態將設置爲「完成」,一個「加載」事件將隨之觸發。
和 HTML 不一樣,CSS 是上下文無關的語法,解析器會將 CSS 文件解析成 StyleSheet 對象,且每一個對象都包含 CSS 規則。CSS 規則對象則包含選擇器和聲明對象,以及其餘與 CSS 語法對應的對象
網絡的模型是同步的。網頁做者但願解析器遇到 <script>
標記時當即解析並執行腳本。文檔的解析將中止,直到腳本執行完畢。若是腳本是外部的,那麼解析過程會中止,直到從網絡同步抓取資源完成後再繼續。此模型已經使用了多年,也在 HTML4 和 HTML5 規範中進行了指定。做者也能夠將腳本標註爲「defer」,這樣它就不會中止文檔解析,而是等到解析結束才執行。HTML5 增長了一個選項,可將腳本標記爲異步,以便由其餘線程解析和執行。
Webkit 和 Firefox 都進行了這項優化。在執行腳本時,其餘線程會解析文檔的其他部分,找出並加載須要經過網絡加載的其餘資源。經過這種方式,資源能夠在並行鏈接上加載,從而提升整體速度。請注意,預解析器不會修改 DOM 樹,而是將這項工做交由主解析器處理;預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的引用。
另外一方面,樣式表有着不一樣的模型。理論上來講,應用樣式表不會更改 DOM 樹,所以彷佛沒有必要等待樣式表並中止文檔解析。但這涉及到一個問題,就是腳本在文檔解析階段會請求樣式信息。若是當時尚未加載和解析樣式,腳本就會得到錯誤的回覆,這樣顯然會產生不少問題。這看上去是一個非典型案例,但事實上很是廣泛。Firefox 在樣式表加載和解析的過程當中,會禁止全部腳本。而對於 Webkit 而言,僅當腳本嘗試訪問的樣式屬性可能受還沒有加載的樣式表影響時,它纔會禁止該腳本。
..........還在進行中