url解析:html
用戶輸入URL地址web
瀏覽器解析URL解析出主機名後端
瀏覽器將主機名轉換成服務器ip地址(瀏覽器先查找本地DNS緩存列表 沒有的話 再向瀏覽器默認的DNS服務器發送查詢請求 同時緩存)瀏覽器
瀏覽器將端口號從URL中解析出來緩存
瀏覽器創建一條與目標Web服務器的TCP鏈接(三次握手)bash
瀏覽器向服務器發送一條HTTP請求報文服務器
服務器向瀏覽器返回一條HTTP響應報文app
關閉鏈接 瀏覽器解析文檔框架
若是文檔中有資源 重複6 7 8 動做 直至資源所有加載完畢dom
html解析:
渲染樹,表明一個文檔的視覺展現,瀏覽器經過它將文檔內容繪製在瀏覽器窗口,展現給用戶,它由按順序展現在屏幕上的一系列矩形對象組成,這些矩形對象都帶有字體,顏色和尺寸,位置等視覺樣式屬性。對於這些矩對象,FireFox稱之爲框架(frame),Webkit瀏覽器稱之爲渲染對象(render object, renderer),後文統稱爲渲染對象。
每個渲染對象都表明着其對應DOM節點的CSS盒子,該盒子包含了尺寸,位置等幾何信息,同時它指向一個樣式對象包含其餘視覺樣式信息。
每個渲染對象都對應着DOM節點,可是非視覺(隱藏,不佔位)DOM元素不會插入渲染樹,如<head>
元素或聲明display: none;
的元素,渲染對象與DOM節點不是簡單的一對一的關係,一個DOM能夠對應一個渲染對象,但一個DOM元素也可能對應多個渲染對象,由於有不少元素不止包含一個CSS盒子,如當文本被折行時,會產生多個行盒,這些行會生成多個渲染對象;又如行內元素同時包含塊元素和行內元素,則會建立一個匿名塊級盒包含內部行內元素,此時一個DOM對應多個矩形對象(渲染對象)。
建立渲染樹後,下一步就是佈局(Layout),或者叫回流(reflow,relayout),這個過程就是經過渲染樹中渲染對象的信息,計算出每個渲染對象的位置和尺寸,將其安置在瀏覽器窗口的正確位置,而有些時候咱們會在文檔佈局完成後對DOM進行修改,這時候可能須要從新進行佈局,也可稱其爲迴流,本質上仍是一個佈局的過程,每個渲染對象都有一個佈局或者回流方法,實現其佈局或迴流。
最後是繪製(paint)階段或重繪(repaint)階段,瀏覽器UI組件將遍歷渲染樹並調用渲染對象的繪製(paint)方法,將內容展示在屏幕上,也有可能在以後對DOM進行修改,須要從新繪製渲染對象,也就是重繪,繪製和重繪的關係能夠參考佈局和迴流的關係。
當它發現了某個部分發生了變化影響了佈局,渲染樹須要從新計算。
改變了某個元素的背景顏色,文字顏色等,不影響元素周圍或內部佈局的屬性,將只會引發瀏覽器的repaint,根據元素的新屬性從新繪製,使元素呈現新的外觀。重繪不會帶來從新佈局,並不必定伴隨重排; Reflow要比Repaint更花費時間,也就更影響性能。因此在寫代碼的時候,要儘可能避免過多的Reflow。
或許是因爲一般會在JavaScript腳本中改變文檔DOM結構,因而瀏覽器以同步方式解析,加載和執行腳本,瀏覽器在解析文檔時,當解析到<script>
標籤時,會解析其中的腳本(對於外鏈的JavaScript文件,須要先加載該文件內容,再進行解析),而後當即執行,這整個過程都會阻塞文檔解析,直到腳本執行完纔會繼續解析文檔。就是說因爲腳本是同步加載和執行的,它會阻塞文檔解析,這也解釋了爲何如今一般建議將<script>
標籤放在</body>
標籤前面,而不是放在<head>
標籤裏。如今HTML5提供defer和async兩個屬性支持延遲和異步加載JavaScript文件
固然咱們能夠經過設置defer
和async
屬性來異步加載不過重要的腳本
這兩個屬性都告訴瀏覽器,他可能會在後臺加載腳本時繼續解析HTML,而後再在加載後執行腳本,這樣腳本下載不會阻止DOM構建和頁面呈現。用戶能夠在全部腳本完成加載以前看到頁面
二者的區別就是他們將在那一刻執行腳本,在這以前咱們須要瞭解瀏覽器爲其加載的每一個網頁追蹤細粒度時間戳
domLoading
: 瀏覽器即將開始解析第一批收到的HTML文檔字節domInteractive
: 表示瀏覽器完成對全部HTML的解析而且DOM構建完成的時間點domContentLoaded
: 表示DOM準備就緒而且沒有樣式表阻止JavaScript執行的時間點domComplete
: 全部處理完成,而且網頁上的全部資源都已經下載完畢loadEvent
: 做爲每一個網頁加載的最後一步,瀏覽器會觸發onload
事件,以便觸發額外的應用邏輯defer
的執行將在domInteractive
完成以後,domContentLoaded
以前開始,他保證腳本將按照他們在HTML中出現的順序執行,而且不會阻塞解析器
async
腳本在完成下載以後和窗口load
事件以前的某一個時間點執行,這意味着異步腳本可能不按他們在HTML中出現的順序執行,這意味着他們可能會阻止DOM構建
<script src="app1.js" defer></script>
<script src="app2.js" defer></script>
<script src="app3.js" defer></script>
複製代碼
defer 屬性表示延遲執行引入的 JavaScript,即這段 JavaScript 加載時 HTML 並未中止解析,這兩個過程是並行的。整個 document 解析完畢且 defer-script 也加載完成以後(這兩件事情的順序無關),會執行全部由 defer-script 加載的 JavaScript 代碼,而後觸發 DOMContentLoaded 事件。
defer 不會改變 script 中代碼的執行順序,示例代碼會按照 一、二、3 的順序執行。因此,defer 與相比普通 script,有兩點區別:載入 JavaScript 文件時不阻塞 HTML 的解析,執行階段被放到 HTML 標籤解析完成以後。
<script src="app.js" async></script>
<script src="ad.js" async></script>
<script src="statistics.js" async></script>
複製代碼
async 屬性表示異步執行引入的 JavaScript,與 defer 的區別在於,若是已經加載好,就會開始執行——不管此刻是 HTML 解析階段仍是 DOMContentLoaded 觸發以後。須要注意的是,這種方式加載的 JavaScript 依然會阻塞 load 事件。換句話說,async-script 可能在 DOMContentLoaded 觸發以前或以後執行,但必定在 load 觸發以前執行。
從上一段也能推出,多個 async-script 的執行順序是不肯定的。值得注意的是,向 document 動態添加 script 標籤時,async 屬性默認是 true
<script>
且沒有defer或async屬性的 標籤時,會觸發頁面渲染,於是若是前面CSS資源還沒有加載完畢時,瀏覽器會等待它加載完畢在執行腳本。參考