1. 程式人生 > >輸入url按回車後發生的一系列不可描述的事情

輸入url按回車後發生的一系列不可描述的事情

前言

最近在研究如何優化首屏白屏時間,大致分為網路部分和js渲染部分,該文章主要是梳理一下從輸入url開始,從客戶端到服務端會發生哪些事情,從哪些地方可以做優化。

過程圖

過程圖

瀏覽器輸入url後發生的過程

1、輸入一個url地址

url遵守一定的語法規則:scheme://host.domain:port/path/filename

  • scheme:定義因特網服務的型別(協議),常見的有http,https,file,ftp等
  • host:定義域主機(http一般預設的是www)
  • demain:定義因特網域名,如baidu.com
  • post:埠號(http一般是80,https一般是443)

2、瀏覽器會先檢視瀏覽器快取--系統快取--路由快取,如有存在快取,就直接顯示。如果沒有,接著第三步

3、瀏覽器查詢域名的ip地址(DNS,域名和ip的對映分散式資料庫)

大致可以分為幾部:

  • 瀏覽器快取

    瀏覽器會快取DNS記錄一段時間,且不同的瀏覽器的快取時間不同

  • 系統快取

    如果在瀏覽器快取裡沒有找到需要的記錄,瀏覽器會做一個系統呼叫(windows裡是gethostbyname)。這樣便可獲得系統快取(host)中的記錄。

  • 路由器快取

    查詢請求發向路由器,它一般會有自己的DNS快取。

  • ISP DNS 快取

    ISP是網際網路服務提供商(Internet Service Provider)的簡稱,ISP有專門的DNS伺服器應對DNS查詢請求。

  • 根伺服器(遞迴搜尋)

    ISP的DNS伺服器還找不到的話,它就會向根伺服器發出請求,進行遞迴查詢(DNS伺服器先問根域名伺服器其的IP地址,然後再問.com域名伺服器,依次類推)

dns流程圖

CDN(Content Delivery Network)就是利用DNS的重定向技術,DNS伺服器會返回一個跟使用者最接近的點的IP地址給使用者,CDN節點的伺服器負責響應使用者的請求,提供所需的內容。

針對DNS的優化大致方向是減少DNS解析的時間,即儘量通過瀏覽器對dns的快取機制來減少對ip的查詢,即減少需要解析的域名的個數

4、瀏覽器給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三次握手

  • 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狀態。

TCP四次揮手

  • HTTPS(http+ssl)的非對稱加密和對稱加密

    • 非對稱加密

      握手過程中,伺服器會發出一張證書(帶著公鑰),客戶端用公鑰加密了一段較短的資料S,並返回給伺服器。伺服器用私鑰解開,拿到S。此時,握手步驟完成,S成為了一個被安全傳輸到對方手中的對稱加密金鑰。此後,伺服器與請求響應,只需要用S作為金鑰進行一次對稱的加密就好。

      證書包含公鑰,所以拿到證書意味著就拿到了對方的公鑰

    • 對稱加密

      約定加密金鑰,請求的資料用金鑰加密,伺服器用金鑰解密

    一次完整的https請求:

    1、客戶端向伺服器傳送https請求(443埠)

    2、tcp三次握手建立tcp連線

    2、伺服器端返回一個安全證書(公鑰)

    3、客戶端收到,並進行驗證,如果沒有問題,就用安全證書(公鑰)加密一個隨機值。併發送給服務端

    4、服務端用私鑰解密,拿到該隨機值

    5、後面的通訊就可以通過隨機值用對稱加密的方式進行了

  • 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不會,因為瀏覽器…

優化 :

  • 通過部署cdn來減緩資料返回的事件
  • 優化握手次數
  • 在頭部設定Accept-Encoding型別,通過返回gzip來減少資料體積
  • 通過設定http快取來優化效能,請移步

5、永久重定向響應

為了優化搜尋引擎,把多個域名進行歸類,如把baidu.com,www.baidu.com,www.baidu.com歸類 返回301,通知瀏覽器跳轉,有利於SEO

6、瀏覽器跟蹤重定向地址,請求頭不變

7、伺服器“處理”請求

8、伺服器發回一個HTML響應

9、瀏覽器開始顯示HTML

  • 處理HTML標記,構建DOM樹。
  • 處理CSS標記,構建CSSOM樹。
  • 將DOM樹和CSSOM樹融合成渲染樹(會忽略不需要渲染的dom)。
  • 根據渲染樹來佈局,計算每個節點的幾何資訊。
  • 在螢幕上繪製各個節點。
  • 中間遇到各種資源時,會進行資源的下載

可能存在問題:

  • 資源下載

    • css下載時會阻塞渲染(帶有media屬性除外,不會阻塞瀏覽器解析)。

    • 遇到 script 標籤時,DOM構建停止,此時控制權移交至js,直到指令碼(下載)執行完畢,此時瀏覽器有優化一般會下載其他資源,但是不會解析。如果js中有對CSSOM的操作,還會先確保CSSOM已經被下載並構建。

    • 圖片資源下載不會產生阻塞。

  • 重繪重排導致重新進行渲染樹的生成

    • 重排(迴流)

      會重新計算佈局,通常由元素的結構、增刪、位置、尺寸變化引起,如:img下載成功後,替換填充頁面img元素,引起尺寸變化;也會由js的屬性值讀取引起,如讀取offset、scroll、cilent、getComputedStyle等資訊。

    • 重繪

      簡單外觀的改變會引起重繪,如顏色變化等。

    • 重排一定重繪。

優化:

  • dom
    • 簡化dom結構,減少DOM樹和渲染樹構建成本,減少頁面元素個數

      如使用列表表格資料分頁,簡單表格不要使用複雜第三方元件等方式。

  • js
    • 將js指令碼標籤放在頁面body底部,減少對其他過程的阻塞。

      延遲執行:對不修改頁面的外鏈script使用defer屬性,使指令碼並行下載不阻塞,下載後不立刻執行,而在所有元素解析之後執行。

      這裡簡單的介紹下defer和async的區別:

      相同點:

      • 載入檔案時不阻塞頁面渲染
      • 對於inline的script(內聯指令碼)無效
      • 使用這兩個屬性的指令碼中不能呼叫document.write方法
      • 有指令碼的onload的事件回撥

      不同點:

      • html的版本html4.0中定義了defer;html5.0中定義了async
      • 每一個async屬性的指令碼都在它下載結束之後立刻執行,可能會打亂原有的順序
      • 每一個defer屬性的指令碼都是在頁面解析完畢之後,按照原本的順序執行
    • 減少和合並不必要的dom相關操作,如使用DocumentFragment、修改classname而不是各項style等,減少對重繪和重排的觸發。

  • css
    • 將css放入head中,提前載入,並防止html渲染後重新結合css引起頁面閃爍。
    • 減少css層級和css選擇器複雜度,提高解析速度,雖然瀏覽器有優化。
    • 使用更高效能的css樣式,如flex代替float。
    • 開啟複合層,如使用3d變換、opacity等,使該元素及其子元素不導致外部的重排,但是也有坑。
    • 合理使用脫離文件流的樣式,減少對外部重排的影響,如absolute。
  • 檔案數量
    • 減少首次下載的檔案數量大小.

      使用圖片懶載入,js的按需載入等方式,使用storage儲存進行js、css檔案的快取(PWA)。

    • 拆分頁面資源,首屏資料優先載入等。

      動態路由、懶載入

10、瀏覽器傳送獲取嵌入在HTML中的靜態資源 11、瀏覽器傳送非同步(AJAX)請求

簡單的介紹下fetch相對於ajax的優缺點

  • 優點
    • 內建promise,鏈式呼叫,也可以使用async await來解決回撥地獄
    • res提供了多種轉換格式的方法,json(),blob()
  • 缺點
    • 預設不帶cookie,帶cookie需要指定credentials = include
    • 需要底層支援,或者使用第三方相容包
    • 不能做超時處理,沒有abort方法
    • 遇到常見的錯誤碼不會報錯,需要手動去封裝

最後

推薦一下自己的個人公眾號:前端每日精讀(每日定時推送一篇前端好文)

前端每日精讀