本文將詳細介紹從輸入URL到頁面加載的全過程css
從輸入URL到頁面加載的主幹流程以下:html
一、瀏覽器構建HTTP Request請求nginx
二、網絡傳輸web
三、服務器構建HTTP Response 響應chrome
四、網絡傳輸後端
五、瀏覽器渲染頁面瀏覽器
一、應用層進行DNS解析緩存
經過DNS將域名解析成IP地址。在解析過程當中,按照瀏覽器緩存
、系統緩存
、路由器緩存
、ISP(運營商)DNS緩存
、根域名服務器
、頂級域名服務器
、主域名服務器
的順序,逐步讀取緩存,直到拿到IP地址服務器
這裏使用DNS預解析,能夠根據瀏覽器定義的規則,提早解析以後可能會用到的域名,使解析結果緩存到系統緩存
中,縮短DNS解析時間,來提升網站的訪問速度網絡
二、應用層生成HTTP請求報文
接着,應用層生成針對目標WEB服務器的HTTP請求報文,HTTP請求報文包括起始行、首部和主體部分
若是訪問的google.com,則起始行可能以下
GET https://www.google.com/ HTTP/1.1
首部包括域名host、keep-alive、User-Agent、Accept-Encoding、Accept-Language、Cookie等信息,可能以下
Host: www.google.com Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 X-Client-Data: CKm1yQEIhbbJAQijtskBCMG2yQEIqZ3KAQioo8oB Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
首部和主體內容之間有一個回車換行(CRLF),主體內容即要傳輸的內容。若是是get請求,則主體內容爲空
三、傳輸層創建TCP鏈接
傳輸層傳輸協議分爲UDP和TCP兩種
UDP是無鏈接的協議,而TCP是可靠的有鏈接的協議,主要表如今:接收方會對收到的數據進行確認、發送方會重傳接收方未確認的數據、接收方會將接收到數據按正確的順序從新排序,並刪除重複的數據、提供了控制擁擠的機制
因爲HTTP協議使用的是TCP協議,爲了方便通訊,將HTTP請求報文按序號分爲多個報文段(segment),並對每一個報文段進行封裝。使用本地一個大於1024以上的隨機TCP源端口(這裏假設是1030)創建到目的服務器TCP80號端口(HTTPS協議對應的端口號是443)的鏈接,TCP源端口和目的端口被加入到報文段中,學名叫協議數據單元(Protocol Data Unit, PDU)。因TCP是一個可靠的傳輸控制協議,傳輸層還會加入序列號、確認號、窗口大小、校驗和等參數,共添加20字節的頭部信息
TCP協議是面向鏈接的,因此它在開始傳輸數據以前須要先創建鏈接。要創建或初始化一個鏈接,兩端主機必須同步雙方的初始序號。同步是經過交換鏈接創建數據分段和初始序號來完成的,在鏈接創建數據分段中包含一個SYN(同步)的控制位。同步須要雙方都發送本身的初始序號,而且發送確認的ACK。此過程就是三次握手
第一次握手:主機A發往主機B,主機A的初始序號是X,設置SYN位,未設置ACK位
第二次握手:主機B發往主機A,主機B的初始序號是Y,確認號(ACK)是X+1,X+1確認號暗示己經收到主機A發往主機B的同步序號。設置SYN位和ACK位
第三次握手:主機A發往主機B,主機A的序號是X+1,確認號是Y+1,Y+1確認號暗示已經收到主機B發往主機A的同步序號。設置ACK位,未設置SYN位
三次握手解決的不只僅有序號問題,還解決了包括窗口大小、MTU(Maximum Transmission Unit,最大傳輸單元),以及所指望的網絡延時等其餘問題
構建TCP請求會增長大量的網絡時延,經常使用的優化方式以下所示
(1)資源打包,合併請求
(2)多使用緩存,減小網絡傳輸
(3)使用keep-alive創建持久鏈接
(4)使用多個域名,增長瀏覽器的資源併發加載數,或者使用HTTP2的管道化鏈接的多路複用技術
四、網絡層使用IP協議來選擇路線
處理來自傳輸層的數據段segment,將數據段segment裝入數據包packet,填充包頭,主要就是添加源和目的IP地址,而後發送數據。在數據傳輸的過程當中,IP協議負責選擇傳送的路線,稱爲路由功能
五、數據鏈路層實現網絡相鄰結點間可靠的數據通訊
爲了保證數據的可靠傳輸,把數據包packet封裝成幀(Frame),並按順序傳送各幀。因爲物理線路的不可靠,發出的數據幀有可能在線路上出錯或丟失,因而爲每一個數據分塊計算出CRC(循環冗餘檢驗),並把CRC添加到幀中,這樣接收方就能夠經過從新計算CRC來判斷數據接收的正確性。一旦出錯就重傳
將數據包packet封裝成幀(Frame),包括幀頭和幀尾。幀尾是添加被稱作CRC的循環冗餘校驗部分。幀頭主要是添加數據鏈路層的地址,即數據鏈路層的源地址和目的地址,即網絡相鄰結點間的源MAC地址和目的MAC地址
六、物理層傳輸數據
數據鏈路層的幀(Frame)轉換成二進制形式的比特(Bit)流,從網卡發送出去,再把比特轉換成電子、光學或微波信號在網絡中傳輸
【總結】
上面的6個步驟可總結爲:DNS解析URL地址、生成HTTP請求報文、構建TCP鏈接、使用IP協議選擇傳輸路線、數據鏈路層保證數據的可靠傳輸、物理層將數據轉換成電子、光學或微波信號進行傳輸
從客戶機到服務器須要經過許多網絡設備, 通常地,包括集線器、交換器、路由器等
【集線器】
集線器是物理層設備,比特流到達集線器後,集線器簡單地對比特流進行放大,從除接收端口之外的全部端口轉發出去
【交換機】
交換機是數據鏈路層設備,比特流到達交換機,交換機除了對比特流進行放大外,還根據源MAC地址進行學習,根據目的MAC地址進行轉發。交換機根據數據幀中的目的MAC地址査詢MAC地址表,把比特流從對應的端口發送出去
【路由器】
路由器是網絡層設備,路由器收到比特流,轉換成幀上傳到數據鏈路層,路由器比較數據幀的目的MAC地址,若是有與路由器接收端口相同的MAC地址,則路由器的數據鏈路層把數據幀進行解封裝,而後上傳到路由器的網絡層,路由器找到數據包的目的IP地址,並查詢路由表,將數據從入端口轉發到出端口。接着在網絡層從新封裝成數據包packet,下沉到數據鏈路層從新封裝成幀frame,下沉到物理層,轉換成二進制比特流,發送出去
服務器接收到這個比特流,把比特流轉換成幀格式,上傳到數據鏈路層,服務器發現數據幀中的目的MAC地址與本網卡的MAC地址相同,服務器拆除數據鏈路層的封裝後,把數據包上傳到網絡層。服務器的網絡層比較數據包中的目的IP地址,發現與本機的IP地址相同,服務器拆除網絡層的封裝後,把數據分段上傳到傳輸層。傳輸層對數據分段進行確認、排序、重組,確保數據傳輸的可靠性。數據最後被傳到服務器的應用層
HTTP服務器,如nginx經過反向代理,將其定位到服務器實際的端口位置,如8080。好比,8080端口對應的是一個NodeJS服務,生成響應報文,報文主體內容是google首頁的HTML頁面
接着,經過傳輸層、網絡層、數據鏈路層的層層封裝,最終將響應報文封裝成二進制比特流,並轉換成其餘信號,如電信號到網絡中傳輸
反向傳輸的過程與正向傳輸的過程相似,就再也不贅述
客戶機接受到二進制比特流以後,把比特流轉換成幀格式,上傳到數據鏈路層,客戶機發現數據幀中的目的MAC地址與本網卡的MAC地址相同,拆除數據鏈路層的封裝後,把數據包上傳到網絡層。網絡層比較數據包中的目的IP地址,發現與本機的IP地址相同,拆除網絡層的封裝後,把數據分段上傳到傳輸層。傳輸層對數據分段進行確認、排序、重組,確保數據傳輸的可靠性。數據最後被傳到應用層
一、若是HTTP響應報文是301或302重定向,則瀏覽器會相應頭中的location再次發送請求
二、瀏覽器處理HTTP響應報文中的主體內容,首先使用loader模塊加載相應的資源
loader模塊有兩條資源加載路徑:主資源加載路徑和派生資源加載路徑。主資源即google主頁的index.html文件 ,派生資源即index.html文件中用到的資源
主資源到達後,瀏覽器的Parser模塊解析主資源的內容,生成派生資源對應的DOM結構,而後根據需求觸發派生資源的加載流程。好比,在解析過程當中,若是遇到img的起始標籤,會建立相應的image元素HTMLImageElement,接着依據img標籤的內容設置HTMLImageElement的屬性。在設置src屬性時,會觸發圖片資源加載,發起加載資源請求
這裏常見的優化點是對派生資源使用緩存
三、使用parse模塊解析HTML、CSS、Javascript資源
【解析HTML】
HTML解析分爲能夠分爲解碼、分詞、解析、建樹四個步驟
(1)解碼:將網絡上接收到的通過編碼的字節流,解碼成Unicode字符
(2)分詞:按照必定的切詞規則,將Unicode字符流切成一個個的詞語(Tokens)
(3)解析:根據詞語的語義,建立相應的節點(Node)
(4)建樹:將節點關聯到一塊兒,建立DOM樹
【解析CSS】
頁面中全部的CSS由樣式表CSSStyleSheet集合構成,而CSSStyleSheet是一系列CSSRule的集合,每一條CSSRule則由選擇器CSSStyleSelector部分和聲明CSSStyleDeclaration部分構成,而CSSStyleDeclaration是CSS屬性和值的Key-Value集合
CSS解析完畢後會進行CSSRule的匹配過程,即尋找知足每條CSS規則Selector部分的HTML元素,而後將其Declaration聲明部分應用於該元素。實際的規則匹配過程會考慮到默認和繼承的CSS屬性、匹配的效率及規則的優先級等因素
【解析JS】
JavaScript通常由單獨的腳本引擎解析執行,它的做用一般是動態地改變DOM樹(好比爲DOM節點添加事件響應處理函數),即根據時間(timer)或事件(event)映射一棵DOM樹到另外一棵DOM樹
簡單來講,通過了Parser模塊的處理,瀏覽器把頁面文本轉換成了一棵節點帶CSS Style、會響應自定義事件的Styled DOM樹
四、構建DOM樹、Render樹及RenderLayer樹
瀏覽器的解析過程就是將字節流形式的網頁內容構建成DOM樹、Render樹及RenderLayer樹的過程
使用parse解析HTML的過程,已經完成了DOM樹的構建,接下來構建Render樹
【Render樹】
Render樹用於表示文檔的可視信息,記錄了文檔中每一個可視元素的佈局及渲染方式
RenderObject是Render樹全部節點的基類,做用相似於DOM樹的Node類。這個類存儲了繪製頁面可視元素所須要的樣式及佈局信息,RenderObject對象及其子類都知道如何繪製本身。事實上繪製Render樹的過程就是RenderObject按照必定順序繪製自身的過程
DOM樹上的節點與Render樹上的節點並非一一對應的。只有DOM樹的根節點及可視節點纔會建立對應的RenderObject節點
【Render Layer樹】
Render Layer樹以層爲節點組織文檔的可視信息,網頁上的每一層對應一個Render Layer對象。RenderLayer樹能夠看做Render樹的稀疏表示,每一個RenderLayer樹的節點都對應着一棵Render樹的子樹,這棵子樹上全部Render節點都在網頁的同一層顯示
RenderLayer樹是基於RenderObject樹構建的,知足必定條件的RenderObject纔會創建對應的RenderLayer節點
下面是RenderLayer節點的建立條件:
(1)網頁的root節點
(2)有顯式的CSS position屬性(relative,absolute,fixed)
(3)元素設置了transform
(4)元素是透明的,即opacity不等於1
(5)節點有溢出(overflow)、alpha mask或者反射(reflection)效果。
(6)元素有CSS filter(濾鏡)屬性
(7)2D Canvas或者WebGL
(8)Video元素
五、佈局和渲染
佈局就是安排和計算頁面中每一個元素大小位置等幾何信息的過程。HTML採用流式佈局模型,基本的原則是頁面元素在順序遍歷過程當中依次按從左至右、從上至下的排列方式肯定各自的位置區域
簡單狀況下,佈局能夠順序遍歷一次Render樹完成,但也有須要迭代的狀況。當祖先元素的大小位置依賴於後代元素或者互相依賴時,一次遍歷就沒法完成佈局,如Table元素的寬高未明確指定而其下某一子元素Tr指定其高度爲父Table高度的30%的狀況
Paint模塊負責將Render樹映射成可視的圖形,它會遍歷Render樹調用每一個Render節點的繪製方法將其內容顯示在一塊畫布或者位圖上,並最終呈如今瀏覽器應用窗口中成爲用戶看到的實際頁面
主要繪製順序以下:
(1)背景顏色
(2)背景圖片
(3)邊框
(4)子呈現樹節點
(5)輪廓
六、硬件加速
開啓硬件渲染,即合成加速,會爲須要單獨繪製的每一層建立一個GraphicsLayer
硬件渲染是指網頁各層的合成是經過GPU完成的,它採用分塊渲染的策略,分塊渲染是指:網頁內容被一組Tile覆蓋,每塊Tile對應一個獨立的後端存儲,當網頁內容更新時,只更新內容有變化的Tile。分塊策略能夠作到局部更新,渲染效率更高
一個Render Layer對象若是須要後端存儲,它會建立一個Render Layer Backing對象,該對象負責Renderlayer對象所須要的各類存儲。若是一個Render Layer對象能夠建立後端存儲,那麼將該RenderLayer稱爲合成層(Compositing Layer)
若是一個Render Layer對象具備如下的特徵之一,那麼它就是合成層:
(1)RenderLayer具備CSS 3D屬性或者CSS透視效果。
(2)RenderLayer包含的RenderObject節點表示的是使用硬件加速的視頻解碼技術的HTML5 」video」元素。
(3) RenderLayer包含的RenderObject節點表示的是使用硬件加速的Canvas2D元素或者WebGL技術。
(4)RenderLayer使用了CSS透明效果的動畫或者CSS變換的動畫。
(5)RenderLayer使用了硬件加速的CSSfilters技術。
(6)RenderLayer使用了剪裁(clip)或者反射(reflection)屬性,而且它的後代中包括了一個合成層。
(7)RenderLayer有一個Z座標比本身小的兄弟節點,該節點是一個合成層
最終的渲染流程以下所示:
【重繪和迴流】
重繪和迴流是在頁面渲染過程當中很是重要的兩個概念。頁面生成之後,腳本操做、樣式表變動,以及用戶操做均可能觸發重繪和迴流
迴流reflow是firefox裏的術語,在chrome中稱爲重排relayout
迴流是指窗口尺寸被修改、發生滾動操做,或者元素位置相關屬性被更新時會觸發佈局過程,在佈局過程當中要計算全部元素的位置信息。因爲HTML使用的是流式佈局,若是頁面中的一個元素的尺寸發生了變化,則其後續的元素位置都要跟着發生變化,也就是從新進行流式佈局的過程,因此被稱之爲迴流
前面介紹過渲染引擎生成的3個樹:DOM樹、Render樹、Render Layer樹。迴流發生在Render樹上。常說的脫離文檔流,就是指脫離渲染樹Render Tree
重繪是指當與視覺相關的樣式屬性值被更新時會觸發繪製過程,在繪製過程當中要從新計算元素的視覺信息,使元素呈現新的外觀
因爲元素的重繪repaint只發生在渲染層 render layer上。因此,若是要改變元素的視覺屬性,最好讓該元素成爲一個獨立的渲染層render layer
下面列舉一些減小回流次數的方法
(1)不要一條一條地修改DOM樣式,而是修改className或者修改style.cssText
(2)在內存中屢次操做節點,完成後再添加到文檔中去
(3)對於一個元素進行復雜的操做時,能夠先隱藏它,操做完成後再顯示
(4)在須要常常獲取那些引發瀏覽器迴流的屬性值時,要緩存到變量中
(5)不要使用table佈局,由於一個小改動可能會形成整個table從新佈局。並且table渲染一般要3倍於同等元素時間
此外,將須要屢次重繪的元素獨立爲render layer渲染層,如設置absolute,能夠減小重繪範圍;對於一些進行動畫的元素,能夠進行硬件渲染,從而避免重繪和迴流