最近在研究如何優化首屏白屏時間,大體分爲網絡部分和js渲染部分,該文章主要是梳理一下從輸入url開始,從客戶端到服務端會發生哪些事情,從哪些地方能夠作優化。css
一、輸入一個url地址html
url遵照必定的語法規則:scheme://host.domain:port/path/filename前端
二、瀏覽器會先查看瀏覽器緩存--系統緩存--路由緩存,若有存在緩存,就直接顯示。若是沒有,接着第三步html5
三、瀏覽器查找域名的ip地址(DNS,域名和ip的映射分佈式數據庫)git
大體能夠分爲幾部:github
瀏覽器緩存web
瀏覽器會緩存DNS記錄一段時間,且不一樣的瀏覽器的緩存時間不一樣ajax
系統緩存數據庫
若是在瀏覽器緩存裏沒有找到須要的記錄,瀏覽器會作一個系統調用(windows裏是gethostbyname)。這樣即可得到系統緩存(host)中的記錄。json
路由器緩存
查詢請求發向路由器,它通常會有本身的DNS緩存。
ISP DNS 緩存
ISP是互聯網服務提供商(Internet Service Provider)的簡稱,ISP有專門的DNS服務器應對DNS查詢請求。
根服務器(遞歸搜索)
ISP的DNS服務器還找不到的話,它就會向根服務器發出請求,進行遞歸查詢(DNS服務器先問根域名服務器其的IP地址,而後再問.com域名服務器,依次類推)
CDN(Content Delivery Network)就是利用DNS的重定向技術,DNS服務器會返回一個跟用戶最接近的點的IP地址給用戶,CDN節點的服務器負責響應用戶的請求,提供所需的內容。
針對DNS的優化大體方向是減小DNS解析的時間,即儘可能經過瀏覽器對dns的緩存機制來減小對ip的查詢,即減小須要解析的域名的個數
四、瀏覽器給web服務器發送一個HTTP(HTTPS)請求
TCP三次握手
瀏覽器得到 IP 地址後,就會對目標服務器發起創建 TCP 鏈接的請求,創建鏈接主要有三個步驟,通常稱爲客戶端與服務器端的三次握手:
第一次握手: 創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;
第二次握手: 服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手: 客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP鏈接成功)狀態,完成三次握手。
TCP四次揮手
客戶端或服務器都可主動發起揮手動做
第一次揮手: 主動關閉方,將FIN置爲1,Seq設置爲Z爲上一次對方傳送過來的Ack值,Ack設置爲X爲Seq值+1。設置好以上值後,將數據發送至被動關閉方(這裏標記爲:B)。而後A進入FIN_WAIT_1狀態。
第二次揮手:B收到了A發送的FIN報文段,向A回覆,Ack設置爲第一次揮手中的Seq值+1,Seq設置爲Y第一次揮手中的Ack值。而後B進入CLOSE_WAIT狀態,A收到B的回覆後,進入FIN_WAIT_2狀態。
第三次揮手:B再次向A發送報文,將FIN置爲1,Ack設置爲X,Seq設置爲Y。而後B進入LAST_ACK狀態,A收到B的報文後,進入TIME_WAIT狀態。
第四次揮手:A收到B發送的FIN報文段,Ack設置爲Y,Seq設置爲X。而後A進入TIME_WAIT狀態,B在收到報文後進入CLOSED狀態,A在發送完報文等待了2MSL時間後進入CLOSED狀態。
HTTPS(http+ssl)的非對稱加密和對稱加密
非對稱加密
握手過程當中,服務器會發出一張證書(帶着公鑰),客戶端用公鑰加密了一段較短的數據S,並返回給服務器。服務器用私鑰解開,拿到S。此時,握手步驟完成,S成爲了一個被安全傳輸到對方手中的對稱加密密鑰。此後,服務器與請求響應,只須要用S做爲密鑰進行一次對稱的加密就好。
證書包含公鑰,因此拿到證書意味着就拿到了對方的公鑰
對稱加密
約定加密密鑰,請求的數據用密鑰加密,服務器用密鑰解密
一次完整的https請求:
一、客戶端向服務器發送https請求(443端口)
二、tcp三次握手創建tcp鏈接
二、服務器端返回一個安全證書(公鑰)
三、客戶端收到,並進行驗證,若是沒有問題,就用安全證書(公鑰)加密一個隨機值。併發送給服務端
四、服務端用私鑰解密,拿到該隨機值
五、後面的通訊就能夠經過隨機值用對稱加密的方式進行了
http默認自帶cookie
在http請求中,cookie是默認自帶的,能夠經過設置cookie的HttpOnly和Secure屬性來進行控制,詳情請移步
請求頭自帶的與tcp相關的屬性
Connection
Connection 頭(header) 決定當前的事務完成後,是否會關閉網絡鏈接。若是該值是「keep-alive」,網絡鏈接就是持久的,不會關閉,使得對同一個服務器的請求能夠繼續在該鏈接上完成。
在http1.0的時候Connection的值默認爲close
在http1.1的時候Connection的值默認爲Keep-Alive
瀏覽器會自發作的事
瀏覽器能安全的添加斜槓,如www.baidu.com ->www.baidu.com/ ,而www.baidu.com/222 ->www.baidu.com/222不會,由於瀏覽器…
優化 :
五、永久重定向響應
爲了優化搜索引擎,把多個域名進行歸類,如把baidu.com,www.baidu.com,www.baidu.com歸類 返回301,通知瀏覽器跳轉,有利於SEO
六、瀏覽器跟蹤重定向地址,請求頭不變
七、服務器「處理」請求
八、服務器發回一個HTML響應
九、瀏覽器開始顯示HTML
可能存在問題:
資源下載
css下載時會阻塞渲染(帶有media屬性除外,不會阻塞瀏覽器解析)。
遇到 script 標籤時,DOM構建中止,此時控制權移交至js,直到腳本(下載)執行完畢,此時瀏覽器有優化通常會下載其餘資源,可是不會解析。若是js中有對CSSOM的操做,還會先確保CSSOM已經被下載並構建。
圖片資源下載不會產生阻塞。
重繪重排致使從新進行渲染樹的生成
重排(迴流)
會從新計算佈局,一般由元素的結構、增刪、位置、尺寸變化引發,如:img下載成功後,替換填充頁面img元素,引發尺寸變化;也會由js的屬性值讀取引發,如讀取offset、scroll、cilent、getComputedStyle等信息。
重繪
簡單外觀的改變會引發重繪,如顏色變化等。
重排必定重繪。
優化:
簡化dom結構,減小DOM樹和渲染樹構建成本,減小頁面元素個數
如使用列表表格數據分頁,簡單表格不要使用複雜第三方組件等方式。
將js腳本標籤放在頁面body底部,減小對其餘過程的阻塞。
延遲執行:對不修改頁面的外鏈script使用defer屬性,使腳本並行下載不阻塞,下載後不馬上執行,而在全部元素解析以後執行。
這裏簡單的介紹下defer和async的區別:
相同點:
不一樣點:
減小和合並沒必要要的dom相關操做,如使用DocumentFragment、修改classname而不是各項style等,減小對重繪和重排的觸發。
減小首次下載的文件數量大小.
使用圖片懶加載,js的按需加載等方式,使用storage存儲進行js、css文件的緩存(PWA)。
拆分頁面資源,首屏數據優先加載等。
動態路由、懶加載
十、瀏覽器發送獲取嵌入在HTML中的靜態資源 十一、瀏覽器發送異步(AJAX)請求
簡單的介紹下fetch相對於ajax的優缺點
推薦一下本身的我的公衆號:前端精讀(每日定時推送一篇前端好文)