天天看點

從輸入URL到頁面加載的全過程

[1]概述

[2]建構請求

[3]網絡傳輸

[4]伺服器處理及反向傳輸

[5]浏覽器渲染

前面的話

  本文将詳細介紹從輸入URL到頁面加載的全過程

概述

  從輸入URL到頁面加載的主幹流程如下:

  1、浏覽器建構HTTP Request請求

  2、網絡傳輸

  3、伺服器建構HTTP Response 響應

  4、網絡傳輸

  5、浏覽器渲染頁面

從輸入URL到頁面加載的全過程

建構請求

  1、應用層進行DNS解析

  通過DNS将域名解析成IP位址。在解析過程中,按照

浏覽器緩存

系統緩存

路由器緩存

ISP(營運商)DNS緩存

根域名伺服器

頂級域名伺服器

主域名伺服器

的順序,逐漸讀取緩存,直到拿到IP位址

  這裡使用DNS預解析,可以根據浏覽器定義的規則,提前解析之後可能會用到的域名,使解析結果緩存到

系統緩存

中,縮短DNS解析時間,來提高網站的通路速度

  2、應用層生成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請求,則主體内容為空

  3、傳輸層建立TCP連接配接

  傳輸層傳輸協定分為UDP和TCP兩種

  UDP是無連接配接的協定,而TCP是可靠的有連接配接的協定,主要表現在:接收方會對收到的資料進行确認、發送方會重傳接收方未确認的資料、接收方會将接收到資料按正确的順序重新排序,并删除重複的資料、提供了控制擁擠的機制

  由于HTTP協定使用的是TCP協定,為了友善通信,将HTTP請求封包按序号分為多個封包段(segment),并對每個封包段進行封裝。使用本地一個大于1024以上的随機TCP源端口(這裡假設是1030)建立到目的伺服器TCP80号端口(HTTPS協定對應的端口号是443)的連接配接,TCP源端口和目的端口被加入到封包段中,學名叫協定資料單元(Protocol Data Unit, PDU)。因TCP是一個可靠的傳輸控制協定,傳輸層還會加入序列号、确認号、視窗大小、校驗和等參數,共添加20位元組的頭部資訊

從輸入URL到頁面加載的全過程

  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,最大傳輸單元),以及所期望的網絡延時等其他問題

從輸入URL到頁面加載的全過程

  建構TCP請求會增加大量的網絡時延,常用的優化方式如下所示

  (1)資源打包,合并請求

  (2)多使用緩存,減少網絡傳輸

  (3)使用keep-alive建立持久連接配接

  (4)使用多個域名,增加浏覽器的資源并發加載數,或者使用HTTP2的管道化連接配接的多路複用技術

  4、網絡層使用IP協定來選擇路線

  處理來自傳輸層的資料段segment,将資料段segment裝入資料包packet,填充標頭,主要就是添加源和目的IP位址,然後發送資料。在資料傳輸的過程中,IP協定負責選擇傳送的路線,稱為路由功能

從輸入URL到頁面加載的全過程

  5、資料鍊路層實作網絡相鄰結點間可靠的資料通信

  為了保證資料的可靠傳輸,把資料包packet封裝成幀(Frame),并按順序傳送各幀。由于實體線路的不可靠,發出的資料幀有可能線上路上出錯或丢失,于是為每個資料分塊計算出CRC(循環備援檢驗),并把CRC添加到幀中,這樣接收方就可以通過重新計算CRC來判斷資料接收的正确性。一旦出錯就重傳

  将資料包packet封裝成幀(Frame),包括幀頭和幀尾。幀尾是添加被稱做CRC的循環備援校驗部分。幀頭主要是添加資料鍊路層的位址,即資料鍊路層的源位址和目的位址,即網絡相鄰結點間的源MAC位址和目的MAC位址

  6、實體層傳輸資料

  資料鍊路層的幀(Frame)轉換成二進制形式的比特(Bit)流,從網卡發送出去,再把比特轉換成電子、光學或微波信号在網絡中傳輸

【總結】

  上面的6個步驟可總結為:DNS解析URL位址、生成HTTP請求封包、建構TCP連接配接、使用IP協定選擇傳輸路線、資料鍊路層保證資料的可靠傳輸、實體層将資料轉換成電子、光學或微波信号進行傳輸

從輸入URL到頁面加載的全過程

網絡傳輸

  從客戶機到伺服器需要通過許多網絡裝置, 一般地,包括集線器、交換器、路由器等

【集線器】

  集線器是實體層裝置,比特流到達集線器後,集線器簡單地對比特流進行放大,從除接收端口以外的所有端口轉發出去

【交換機】

  交換機是資料鍊路層裝置,比特流到達交換機,交換機除了對比特流進行放大外,還根據源MAC位址進行學習,根據目的MAC位址進行轉發。交換機根據資料幀中的目的MAC位址査詢MAC位址表,把比特流從對應的端口發送出去

【路由器】

  路由器是網絡層裝置,路由器收到比特流,轉換成幀上傳到資料鍊路層,路由器比較資料幀的目的MAC位址,如果有與路由器接收端口相同的MAC位址,則路由器的資料鍊路層把資料幀進行解封裝,然後上傳到路由器的網絡層,路由器找到資料包的目的IP位址,并查詢路由表,将資料從入端口轉發到出端口。接着在網絡層重新封裝成資料包packet,下沉到資料鍊路層重新封裝成幀frame,下沉到實體層,轉換成二進制比特流,發送出去

從輸入URL到頁面加載的全過程

伺服器處理及反向傳輸

  伺服器接收到這個比特流,把比特流轉換成幀格式,上傳到資料鍊路層,伺服器發現資料幀中的目的MAC位址與本網卡的MAC位址相同,伺服器拆除資料鍊路層的封裝後,把資料包上傳到網絡層。伺服器的網絡層比較資料包中的目的IP位址,發現與本機的IP位址相同,伺服器拆除網絡層的封裝後,把資料分段上傳到傳輸層。傳輸層對資料分段進行确認、排序、重組,確定資料傳輸的可靠性。資料最後被傳到伺服器的應用層

  HTTP伺服器,如nginx通過反向代理,将其定位到伺服器實際的端口位置,如8080。比如,8080端口對應的是一個NodeJS服務,生成響應封包,封包主體内容是google首頁的HTML頁面

  接着,通過傳輸層、網絡層、資料鍊路層的層層封裝,最終将響應封包封裝成二進制比特流,并轉換成其他信号,如電信号到網絡中傳輸

  反向傳輸的過程與正向傳輸的過程類似,就不再贅述

浏覽器渲染

  客戶機接受到二進制比特流之後,把比特流轉換成幀格式,上傳到資料鍊路層,客戶機發現資料幀中的目的MAC位址與本網卡的MAC位址相同,拆除資料鍊路層的封裝後,把資料包上傳到網絡層。網絡層比較資料包中的目的IP位址,發現與本機的IP位址相同,拆除網絡層的封裝後,把資料分段上傳到傳輸層。傳輸層對資料分段進行确認、排序、重組,確定資料傳輸的可靠性。資料最後被傳到應用層

  1、如果HTTP響應封包是301或302重定向,則浏覽器會相應頭中的location再次發送請求

  2、浏覽器處理HTTP響應封包中的主體内容,首先使用loader子產品加載相應的資源

  loader子產品有兩條資源加載路徑:主資源加載路徑和派生資源加載路徑。主資源即google首頁的index.html檔案 ,派生資源即index.html檔案中用到的資源

  主資源到達後,浏覽器的Parser子產品解析主資源的内容,生成派生資源對應的DOM結構,然後根據需求觸發派生資源的加載流程。比如,在解析過程中,如果遇到img的起始标簽,會建立相應的image元素HTMLImageElement,接着依據img标簽的内容設定HTMLImageElement的屬性。在設定src屬性時,會觸發圖檔資源加載,發起加載資源請求

  這裡常見的優化點是對派生資源使用緩存

  3、使用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樹

  4、建構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元素

  5、布局和渲染

  布局就是安排和計算頁面中每個元素大小位置等幾何資訊的過程。HTML采用流式布局模型,基本的原則是頁面元素在順序周遊過程中依次按從左至右、從上至下的排列方式确定各自的位置區域

  簡單情況下,布局可以順序周遊一次Render樹完成,但也有需要疊代的情況。當祖先元素的大小位置依賴于後代元素或者互相依賴時,一次周遊就無法完成布局,如Table元素的寬高未明确指定而其下某一子元素Tr指定其高度為父Table高度的30%的情況

  Paint子產品負責将Render樹映射成可視的圖形,它會周遊Render樹調用每個Render節點的繪制方法将其内容顯示在一塊畫布或者位圖上,并最終呈現在浏覽器應用視窗中成為使用者看到的實際頁面

  主要繪制順序如下:

  (1)背景顔色

  (2)背景圖檔

  (3)邊框

  (4)子呈現樹節點

  (5)輪廓

  6、硬體加速

  開啟硬體渲染,即合成加速,會為需要單獨繪制的每一層建立一個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坐标比自己小的兄弟節點,該節點是一個合成層

  最終的渲染流程如下所示:

從輸入URL到頁面加載的全過程

【重繪和回流】

   重繪和回流是在頁面渲染過程中非常重要的兩個概念。頁面生成以後,腳本操作、樣式表變更,以及使用者操作都可能觸發重繪和回流

  回流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,可以減少重繪範圍;對于一些進行動畫的元素,可以進行硬體渲染,進而避免重繪和回流

好的代碼像粥一樣,都是用時間熬出來的

從輸入URL到頁面加載的全過程

繼續閱讀