從輸入URL到頁面渲染到底發生了什麼

一個很是巨大的問題,涉及的領域好多……css

稍微理了下主幹,固然不是我本身理的,綜合了不少前輩的文章,列表以下:html

http://web.jobbole.com/94150/node

https://www.cnblogs.com/daijinxue/p/6640153.htmlweb

https://segmentfault.com/a/1190000006879700算法

https://segmentfault.com/a/1190000003925803apache

https://blog.csdn.net/u012194956/article/details/79110212json

從輸入url到頁面加載發生了什麼

總覽

  • 瀏覽器地址欄輸入URL並回車
  • 瀏覽器查找當前URL是否存在緩存,並比較緩存是否過時
  • DNS解析URL對應的IP
  • 根據IP創建TCP鏈接(三次握手)
  • 發送HTTP請求
  • 服務器處理請求,瀏覽器接受HTTP響應
  • 瀏覽器解析並渲染頁面
  • 關閉TCP鏈接(四次握手)

瀏覽器進程/線程模型,JS的運行機制

多進程的瀏覽器

瀏覽器是多進程的,可能包括:segmentfault

  • 瀏覽器主進程:負責協調、主控,只有一個
  • 瀏覽器渲染進程(內核):每一個Tab頁面有一個互不影響的進程,負責頁面渲染、腳本執行、事件處理等(有時候會優化,多個空白Tab會合併成一個進程)
  • 第三方插件進程:每種類型的插件對應一個進程,僅當使用該插件時才建立
  • GPU進程:最多一個,用於3D繪製

多線程的瀏覽器內核

每一個Tab的瀏覽器內核進程是多線程的,包括:瀏覽器

  • GUI渲染線程
  • JS引擎線程
  • 事件觸發線程
  • 定時觸發器線程
  • 異步HTTP請求線程

JS引擎是瀏覽器內核進程中的一個單線程。緩存

解析URL

URL的幾大部分:

  • protocal 協議頭:HTTP,HTTPS,FTP
  • host 主機域名或IP地址
  • port 端口號,http默認80,https默認443
  • path 目錄路徑
  • query 查詢參數
  • fragment #後的哈希值,通常用來定位到某個位置

HTTP與HTTPS

HTTP的缺點:

  • 通訊使用明文,內容可能被竊聽
  • 不驗證通訊方身份,可能遭遇假裝
  • 沒法驗證報文的完整性,有可能被篡改

HTTP+加密+認證+完整性保護=HTTPS

  • HTTPS是身披SSL外殼的HTTP:一般狀況下HTTP是直接和TCP層進行通訊的。當使用SSL(安全套接字)時,則演變成HTTP先和SSL通訊,SSL再和TCP通訊 image

SSL

  • 對稱加密:加密和解密用同一個密鑰,易被截取密鑰
  • 非對稱加密(公開密鑰加密):發送密文一方使用對方的共有密鑰進行加密處理,對方收到加密信息後,再使用本身的私有密鑰進行解密。
  • HTTPS採用兩者結合的方式,由於非對稱加密相比對稱加密處理速度較慢**,因此使用非對稱加密傳輸對稱加密的共享密鑰,再使用共享密鑰進行通訊。** -** 公開密鑰的認證是要錢的**!私有密鑰保存在服務器端。

SSL/TLS握手流程

1. 瀏覽器請求創建SSL連接,並向服務端發送一個隨機數–Client random和客戶端支持的加密方法,好比RSA加密,此時是明文傳輸。 2. 服務端從中選出一組加密算法與Hash算法,回覆一個隨機數–Server random,並將本身的身份信息以證書的形式發回給瀏覽器 (證書裏包含了網站地址,非對稱加密的公鑰,以及證書頒發機構等信息) 3. 瀏覽器收到服務端的證書後 - 驗證證書的合法性(頒發機構是否合法,證書中包含的網址是否和正在訪問的同樣),若是證書信任,則瀏覽器會顯示一個小鎖頭,不然會有提示 - 用戶接收證書後(無論信不信任),瀏覽會生產新的隨機數–Premaster secret,而後證書中的公鑰以及指定的加密方法加密`Premaster secret`,發送給服務器。 - 利用Client random、Server random和Premaster secret經過必定的算法生成HTTP連接數據傳輸的對稱加密key-`session key` - 使用約定好的HASH算法計算握手消息,並使用生成的`session key`對消息進行加密,最後將以前生成的全部信息發送給服務端。 4. 服務端收到瀏覽器的回覆 - 利用已知的加解密方式與本身的私鑰進行解密,獲取`Premaster secret` - 和瀏覽器相同規則生成`session key` - 使用`session key`解密瀏覽器發來的握手消息,並驗證Hash是否與瀏覽器發來的一致 - 使用`session key`加密一段握手消息,發送給瀏覽器 5. 瀏覽器解密並計算握手消息的HASH,若是與服務端發來的HASH一致,此時握手過程結束, 

以後全部的https通訊數據將由以前瀏覽器生成的session key並利用對稱加密算法進行加密

HTTPS的好處

  • SEO:搜索引擎排名更高
  • 安全性:
    • 使用https協議可認證用戶和服務器,確保數據發送到正確的客戶機和服務器;
    • https協議是由SSL+http協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程當中不被竊取、改變,確保數據的完整性
    • https是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增長了中間人攻擊的成本。

HTTPS的缺點

  • 使頁面加載時間延長50%,增長10%-20%的好點
  • 影響緩存,鄭家數據開銷
  • 加密範圍有限,在黑客攻擊、拒絕服務攻擊、瀏覽器劫持方面沒什麼做用
  • SSL整數的信用鏈體系並不安全
  • 費用
  • 握手協議費時
  • 佔用服務器資環高

瀏覽器緩存

強制緩存(不須要向瀏覽器發起請求)判斷HTTP首部字段:cache-control,Expires。

  • cache-control中的max-age保存一個相對時間。例如Cache-Control: max-age = 484200,表示瀏覽器收到文件後,緩存在484200s內均有效。
  • Expires是一個絕對時間,即服務器時間。瀏覽器檢查當前時間,若是還沒到失效時間就直接使用緩存文件。可是該方法存在一個問題:服務器時間與客戶端時間可能不一致。所以該字段已經不多使用。
  • 若是同時存在cache-control和Expires,瀏覽器老是優先使用cache-control。

對比緩存(須要向服務器發送請求)經過HTTP的last-modified,Etag字段進行判斷

  • last-modified是第一次請求資源時,服務器返回的字段,表示最後一次更新的時間。下一次瀏覽器請求資源時就發送if-modified-since字段。服務器用本地Last-modified時間與if-modified-since時間比較,若是不一致則認爲緩存已過時並返回新資源給瀏覽器;若是時間一致則發送304狀態碼,讓瀏覽器繼續使用緩存。

  • Etag:資源的實體標識(哈希字符串),當資源內容更新時,Etag會改變。服務器會判斷Etag是否發生變化,若是變化則返回新資源,不然返回304。 image

DNS解析

經過域名查找目標文件所在主機的IP地址 查找過程: 查找過程

  • 瀏覽器搜索本身的 DNS 緩存(維護一張域名與 IP 地址的對應表);

  • 搜索操做系統中的 DNS 緩存(維護一張域名與 IP 地址的對應表);

  • 搜索操做系統的 hosts 文件( Windows 環境下,維護一張域名與 IP 地址的對應表);

  • 操做系統將域名發送至 LDNS**(本地區域名服務器**,若是你在學校接入互聯網,則 LDNS 服務器就在學校,若是經過電信接入互聯網,則 LDNS 服務器就在你當地的電信那裏。)LDNS 查詢 本身的 DNS 緩存(通常查找成功率在 80% 左右),查找成功則返回結果,失敗則發起一個迭代 DNS 解析請求;

    • LDNS 向 Root Name Server (根域名服務器,其雖然沒有每一個域名的的具體信息,但存儲了負責每一個域,如 com、net、org等的解析的頂級域名服務器的地址)發起請求,此處,Root Name Server 返回 com 域的頂級域名服務器的地址;

    • LDNS 向 com 域的頂級域名服務器發起請求,返回 baidu.com 域名服務器地址;

    • LDNS 向baidu.com 域名服務器發起請求,獲得 www.baidu.com 的 IP 地址;

  • LDNS 將獲得的 IP 地址返回給操做系統,同時本身也將 IP 地址緩存起來;

  • 操做系統將 IP 地址返回給瀏覽器,同時本身也將 IP 地址緩存起來;

  • 至此,瀏覽器已經獲得了域名對應的 IP 地址。

DNS優化

DNS緩存

NS存在着多級緩存,從離瀏覽器的距離排序的話,有如下幾種: 瀏覽器緩存,系統緩存,路由器緩存,IPS服務器緩存,根域名服務器緩存,頂級域名服務器緩存,主域名服務器緩存

DNS負載均衡

DNS能夠返回一個合適的機器的IP給用戶,例如能夠根據每臺機器的負載量,該機器離用戶地理位置的距離等等,這種過程就是DNS負載均衡,又叫作DNS重定向。

TCP鏈接(三次握手)

image上圖部分標誌說明:

(1)ACK:TCP規定,只有當ACK=1時有效,也規定鏈接創建後全部發送的報文的ACK必須爲1

(2)SYN(SYNchronization):在鏈接創建時用來同步序號。當SYN=1而ACK=0時,代表這個是一個鏈接請求報文。對方若贊成創建鏈接,則響應報文中SYN=1,ACK=1。所以,SYN置1表示這是一個鏈接請求或鏈接接受報文。

(3)FIN(finish):終結的意思,用來釋放一個鏈接。當FIN=1時,代表此報文段的發送方的數據已經發送完畢,並請求釋放鏈接。

三次握手

(1)第一次握手:創建鏈接。客戶端發送鏈接請求報文段,將SYN位置1,序列號seq(sequence number)爲x;而後,客戶端進入SYN_SEND狀態,等待服務器的確認

(2)第二次握手:服務器收到SYN報文段服務器收到客戶端的SYN報文段,須要對這個SYN報文段進行確認,ACK位置1,確認號ack(acknowledgement number)爲x+1;同時,本身還要發送SYN請求信息,將SYN位置1,序列號seq爲y;服務器將上述SYN+ACK報文段一併發送給客戶端,此時服務器進入SYN_RECV狀態

(3)第三次握手:客戶端收到服務器的SYN+ACK報文段:而後將確認號ack設置爲y+1,向服務器發送ACK報文段。這個報文段發送完畢後,客戶端和服務器都進入ESTABLISHED狀態,完成TCP三次握手,以後能夠開始傳數據 !

HTTP請求

  • HTTP請求報文是由三部分組成: 請求行, 請求報頭和請求正文。

請求行

Method Request-URL HTTP-Version CRLF eg: GET index.html HTTP/1.1 
  • 經常使用的方法有: GET, POST, PUT, DELETE, OPTIONS, HEAD。

請求報頭

  • 請求報頭容許客戶端向服務器傳遞請求的附加信息和客戶端自身的信息。
  • 常見的請求報頭有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。
  • Accept用於指定客戶端用於接受哪些類型的信息,Accept-Encoding與Accept相似,它用於指定接受的編碼方式。Connection設置爲Keep-alive用於告訴客戶端本次HTTP請求結束以後並不須要關閉TCP鏈接,這樣可使下次HTTP請求使用相同的TCP通道,節省TCP鏈接創建的時間。

請求正文

當使用POST, PUT等方法時,一般須要客戶端向服務器傳遞數據。這些數據就儲存在請求正文中。在請求包頭中有一些與請求正文相關的信息,例如: 如今的Web應用一般採用Rest架構,請求的數據格式通常爲json。這時就須要設置Content-Type: application/json。

五層因特爾協議棧

1.應用層(dns,http) DNS解析成IP併發送http請求

2.傳輸層(tcp,udp) 創建tcp鏈接(三次握手)

3.網絡層(IP,ARP) IP尋址

4.數據鏈路層(PPP) 封裝成幀

5.物理層(利用物理介質傳輸比特流) 物理傳輸(而後傳輸的時候經過雙絞線,電磁波等各類介質) 從客戶端發出http請求到服務器接收,中間會通過一系列的流程。

  • 從應用層的發送http請求
  • 到傳輸層經過三次握手創建tcp/ip鏈接
  • 再到網絡層的ip尋址
  • 再到數據鏈路層的封裝成幀
  • 最後到物理層的利用物理介質傳輸。
  • ISO七層模型:物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層

http1.0 1.1 2 的區別

長鏈接與鏈接

首先看tcp/ip層面的定義:

  • 長鏈接:一個tcp/ip鏈接上能夠連續發送多個數據包,在tcp鏈接保持期間,若是沒有數據包發送,須要雙方發檢測包以維持此鏈接,通常須要本身作在線維持(相似於心跳包)
  • 短鏈接:通訊雙方有數據交互時,就創建一個tcp鏈接,數據發送完成後,則斷開此tcp鏈接

http1.0,http1.1

  • http1.0中,默認使用的是短鏈接,也就是說,瀏覽器沒進行一次http操做,就創建一次鏈接,任務結束就中斷鏈接,譬如每個靜態資源請求時都是一個單獨的鏈接
  • http1.1起,默認使用長鏈接,使用長鏈接會有這一行Connection: keep-alive,在長鏈接的狀況下,當一個網頁打開完成後,客戶端和服務端之間用於傳輸http的tcp鏈接不會關閉,若是客戶端再次訪問這個服務器的頁面,會繼續使用這一條已經創建的鏈接
  • keep-alive不會永遠保持,它有一個持續時間,通常在服務器中配置(如apache),另外長鏈接須要客戶端和服務器都支持時纔有效

HTTP2.0

HTTP2.0 與http1.1
  • http1.1中,每請求一個資源,都是須要開啓一個tcp/ip鏈接的,因此對應的結果是,每個資源對應一個tcp/ip請求,因爲tcp/ip自己有併發數限制,因此當資源一多,速度就顯著慢下來
  • http2.0中,一個tcp/ip請求能夠請求多個資源,也就是說,只要一次tcp/ip請求,就能夠請求若干個資源,分割成更小的幀請求,速度明顯提高。

HTTP2.0特性

  • 多路複用(一個tcp/ip能夠請求多個資源)
  • 首部壓縮(HTTP頭部壓縮,減小體積)
  • 二進制分幀(在應用層和傳輸層之間增長二進制分幀層,改進傳輸性能,實現低延遲和高吞吐量)
  • 服務端推送(服務端能夠對客戶端的一個請求發出多個響應,能夠主動通知客戶端)
  • 請求優先級(若是流被賦予了優先級,它就會基於這個優先級來處理,由服務器決定須要多少資源來處理該請求。)

服務器處理請求並返回HTTP報文

通用頭部(狀態碼)

Request Url: 請求的web服務器地址 Request Method: 請求方式 (Get、POST、OPTIONS、PUT、HEAD、DELETE、CONNECT、TRACE) Status Code: 請求的返回狀態碼,如200表明成功 Remote Address: 請求的遠程服務器地址(會轉爲IP

1xx:指示信息–表示請求已接收,繼續處理。

2xx:成功–表示請求已被成功接收、理解、接受。

3xx:重定向–要完成請求必須進行更進一步的操做。

4xx:客戶端錯誤–請求有語法錯誤或請求沒法實現。

5xx:服務器端錯誤–服務器未能實現合法的請求。

  • 平時遇到比較常見的狀態碼有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500(分別表示什麼請自行查找)。

響應報頭,響應報文

  • 常見的響應報頭字段有: Server, Connection...。
  • 服務器返回給瀏覽器的文本信息,一般HTML, CSS, JS, 圖片等文件就放在這一部分。

image

瀏覽器獲取html,解析,渲染

過程以下

  • 解析HTML,生成DOM樹
  • 解析CSS,生成CSS規則樹
  • 合併CSS和DOM數,生成render樹
  • 佈局render樹(layout/reflow),負責各元素尺寸、位置的計算
  • 繪製render樹(paint),繪製頁面像素信息
  • 瀏覽器將各層信息發送給GPU,GPU將各層合成,顯示在屏幕上 image

HTML解析,構建DOM

  • Bytes → characters → tokens → nodes → DOM
  1. Conversion轉換:瀏覽器將得到的HTML內容(Bytes)基於他的編碼轉換爲單個字符

  2. Tokenizing分詞:瀏覽器按照HTML規範標準將這些字符轉換爲不一樣的標記token。每一個token都有本身獨特的含義以及規則集

  3. Lexing詞法分析:分詞的結果是獲得一堆的token,此時把他們轉換爲對象,這些對象分別定義他們的屬性和規則

  4. DOM構建:由於HTML標記定義的就是不一樣標籤之間的關係,這個關係就像是一個樹形結構同樣 例如:body對象的父節點就是HTML對象,而後段略p對象的父節點就是body對象

生成CSSOM樹

過程同上

構建渲染樹

image

  • 通常來講,渲染樹和DOM樹相對應的,但不是嚴格意義上的一一對應

  • 由於有一些不可見的DOM元素不會插入到渲染樹中,如head這種不可見的標籤或者display: none等

渲染

image

  1. 計算CSS樣式

  2. 構建渲染樹

  3. 佈局(迴流,Layout,Reflow),主要定位座標和大小,是否換行,各類position overflow z-index屬性

  4. 繪製(重繪,Repaint),將圖像繪製出來

迴流與重繪

  • Layout,也稱爲Reflow,即迴流。通常意味着元素的內容、結構、位置或尺寸發生了變化,須要從新計算樣式和渲染樹
  • Repaint,即重繪。意味着元素髮生的改變只是影響了元素的一些外觀之類的時候(例如,背景色,邊框顏色,文字顏色等),此時只須要應用新樣式繪製這個元素就能夠了

什麼會引發迴流

1.頁面渲染初始化

2.DOM結構改變,好比刪除了某個節點

3.render樹變化,好比減小了padding

4.窗口resize

5.最複雜的一種:獲取某些屬性,引起迴流, 不少瀏覽器會對迴流作優化,會等到數量足夠時作一次批處理迴流, 可是除了render樹的直接變化,當獲取一些屬性時,瀏覽器爲了得到正確的值也會觸發迴流,這樣使得瀏覽器優化無效,包括 (1)offset(Top/Left/Width/Height) (2) scroll(Top/Left/Width/Height) (3) cilent(Top/Left/Width/Height) (4) width,height (5) 調用了getComputedStyle()或者IE的currentStyle

  1. 元素幾何屬性變化,margin,padding,height,width,border
  • 迴流必定伴隨着重繪,重繪卻能夠單獨出現

優化方案

  • 減小逐項更改樣式,最好一次性更改style,或者將樣式定義爲class並一次性更新
  • 避免循環操做dom,建立一個documentFragment或div,在它上面應用全部DOM操做,最後再把它添加到window.document
    • (1)DocumentFragment 節點不屬於文檔樹,繼承的 parentNode 屬性老是 null。不過它有一種特殊的行爲,該行爲使得它很是有用,即當請求把一個 DocumentFragment 節點插入文檔樹時,插入的不是 DocumentFragment 自身,而是它的全部子孫節點。這使得 DocumentFragment 成了有用的佔位符,暫時存放那些一次插入文檔的節點。它還有利於實現文檔的剪切、複製和粘貼操做。其實他就是一個遊離在DOM樹外面的容器,因此你在把它插入文檔節點以前,隨便給他增刪節點都不會引發迴流
    • (2)使用display:none,只引起兩次迴流和重繪。道理跟上面的同樣。由於display:none的元素不會出如今render樹
    • (3)使用cloneNode和replaceChild技術,引起一次迴流和重繪(這條其實沒太明白)
  • 避免屢次讀取offset等屬性。沒法避免則將它們緩存到變量
  • 將複雜的元素絕對定位或固定定位,使得它脫離文檔流,不然迴流代價會很高
  • 儘可能不要使用表格佈局,若是沒有定寬表格一列的寬度由最寬的一列決定,那麼極可能在最後一行的寬度超出以前的列寬,引發總體迴流形成table可能須要屢次計算才能肯定好其在渲染樹中節點的屬性,一般要花3倍於同等元素的時間。

資源外鏈的下載

遇到外鏈時的處理

  • 遇到外鏈時,會單獨開啓一個下載線程去下載資源(http1.1中是每個資源的下載都要開啓一個http請求,對應一個tcp/ip連接)

遇到CSS樣式資源

CSS資源的處理有幾個特色:

  • CSS下載時異步,不會阻塞瀏覽器構建DOM樹
  • 會阻塞渲染,也就是在構建render時,會等到css下載解析完畢後才進行(這點與瀏覽器優化有關,防止css規則不斷改變,避免了重複的構建)
  • media query聲明的CSS是不會阻塞渲染的

遇到JS腳本資源

JS腳本資源的處理有幾個特色:

  • 阻塞瀏覽器的解析,也就是說發現一個外鏈腳本時,需等待腳本下載完成並執行後纔會繼續解析HTML
  • 瀏覽器的優化,通常現代瀏覽器有優化,在腳本阻塞時,也會繼續下載其它資源(固然有併發上限),可是雖然腳本能夠並行下載,解析過程仍然是阻塞的,也就是說必須這個腳本執行完畢後纔會接下來的解析,並行下載只是一種優化而已
  • defer與async,普通的腳本是會阻塞瀏覽器解析的,可是能夠加上defer或async屬性,這樣腳本就變成異步了,能夠等到解析完畢後再執行 詳見異步加載JS

遇到img圖片類資源

  • 遇到圖片等資源時,直接就是異步下載,不會阻塞解析,下載完畢後直接用圖片替換原有src的地方

loaded和domcontentloaded

簡單的對比:

  • DOMContentLoaded: 事件觸發時,僅當DOM加載完成,不包括樣式表,圖片(譬如若是有async加載的腳本就不必定完成)
  • load: 事件觸發時,頁面上全部的DOM,樣式表,腳本,圖片都已經加載完成了

怎麼提升CSS加載速度?

  • 使用CDN
  • 將CSS壓縮
  • 合理使用緩存
  • 減小HTTP請求數,多個CSS合併

JS引擎解析過程

JS的解釋階段

  • JS是解釋型語音,因此它無需提早編譯,而是由解釋器實時運行
  • 核心的JIT編譯器將源碼編譯成機器碼運行

JS的預處理階段

  • 分號補全
  • 變量提高

JS的執行階段

  • 執行上下文,執行堆棧概念(如全局上下文,當前活動上下文)
  • VO(變量對象)和AO(活動對象)
  • 做用域鏈
  • this機制等

斷開TCP鏈接(四次揮手)

image

  • 第一次揮手是瀏覽器發完數據後,發送FIN請求斷開鏈接。
  • 第二次揮手是服務器發送ACK表示贊成,若是在這一次服務器也發送FIN請求斷開鏈接彷佛也沒有不妥,但考慮到服務器可能還有數據要發送,因此服務器發送FIN應該放在第三次揮手中。
  • 這樣瀏覽器須要返回ACK表示贊成,也就是第四次揮手

    注:

    • 爲何服務器在接到斷開請求時不當即贊成斷開:當服務器收到斷開鏈接的請求時,可能仍然有數據未發送完畢,全部服務器先發送確認信號,等全部數據發送完畢後再贊成斷開。

    • 第四次握手後,主機發送確認信號後並無當即斷開鏈接,而是等待了 2 個報文傳送週期,緣由是:若是第四次握手的確認信息丟失,服務器將會從新發送第三次握手的斷開鏈接的信號,而服務器發覺丟包與從新發送的斷開鏈接到達主機的時間正好爲 2 個報文傳輸週期。

相關文章
相關標籤/搜索