一個頁面從輸入URL到載入顯示完成,發生了什麼?

keywords發表於2019-02-16

面試經典題——URL載入

一、涉及基本知識點:

1. 計算機網路

  1. 五層因特爾協議棧:

    • 應用層(dns、http):DNS解析成IP並完成http請求傳送;
    • 傳輸層(tcp、udp):三次握手四次揮手模式建立tcp連線;
    • 網路層(IP、ARP):IP定址;
    • 資料鏈路層(PPP):將請求資料封裝成幀;
    • 物理層:利用物理介質傳輸位元流(傳輸的時候通過雙絞線、電磁波等)
    • OIS七層框架:多了兩層即,會話層(處理兩個通訊系統中交換資訊的表示方式)和表示層(管理不同使用者和程式之間的對話)。
  2. get和post的區別

    • get產生一個tcp資料包,post產生兩個
    • get請求時會把headers和data資料一起傳送出去;
    • post請求時,瀏覽器先傳送headers,伺服器100繼續,瀏覽器再傳送data。
  3. DNS查詢得到IP

    1. 請求資訊:首先檢視域名的本地DNS快取,該快取儲存計算機最近檢索到的資訊,如果計算機不知道答案,那麼就需要執行一個DNS查詢來查詢答案;
    2. 詢問遞迴式DNS伺服器:

      • 如果資訊不儲存在本地,計算機會聯絡您的ISP(網路提供商)的遞迴DNS伺服器;
      • 這些專用計算機會為你執行一個DNS查詢工作;
      • 遞迴伺服器有自己的快取,所以這個查詢過程通常在這裡完成,並將資訊還回給使用者;
    3. 詢問根域名伺服器

      • 如果遞迴伺服器沒有答案,他們會查詢根域名伺服器;
      • 根域名伺服器是一種計算機,它扮演著一種DNS的電話接線員的角色,他們不知道答案,但可以將我們的疑問指向知道在哪裡可以找到答案的人。
    4. 詢問TLD域名伺服器:

      • 根域名伺服器將檢視請求的第一部分,按從右到左的順序,從www.dyn.com中找到.com,並將請求指向.com對應的頂級域名伺服器(TLD).com;
      • 每個TLD,如(.com,.org,.us)都有自己的頂級域名伺服器,
      • 這些伺服器沒有我們需要的資訊,但他們可以直接將我們引導到有資訊的伺服器。
    5. 詢問權威的DNS伺服器

      • TLD域名伺服器會繼續檢查請求的下一部分(dyn)www.dyn.com,並將查詢指向負責此特定域名的伺服器;
      • 這些權威的伺服器將負責瞭解關於特定域的所有資訊,並將資訊儲存在DNS記錄。
    6. 找回記錄:
      -遞迴伺服器從權威伺服器中檢索dyn.com的記錄,並將記錄儲存在本地快取;

      • 如果其他任何人請求dyn.com的主機記錄,遞迴伺服器已經有答案了,並不需要再次進行查詢;
      • 所有記錄都有一個期限,一段時間後,遞迴伺服器將需要要求一個新的記錄副本,以確保資訊不回過時。
    7. 接收答案:

      • 有了答案,遞迴伺服器將記錄返回到計算機,
      • 您的計算機將記錄儲存在快取中,從記錄中讀取IP地址,然後將這些資訊傳遞給瀏覽器;
      • 然後瀏覽器就可以根據IP地址和伺服器進行連線建立。
  4. TCPIP請求

    • http的本質就是TCPIP請求;
    • 需要經歷3次握手建立連線,4次揮手斷開連線;
    • TCP將http長報文劃分為短報文,通過三次握手與伺服器端建立連線,進行可靠傳輸。
    • 三次握手:

      • 客戶端:你是XXX服務端嗎?
      • 服務端: 我是XXX服務端,你是客戶端嗎?
      • 客服端: 是的,我是客戶端
      • 建立連線成功後,接下來就可以進行正式的傳輸資料。
    • 四次揮手斷開連線

      • 主動方:我已經關閉了向你那邊的資訊傳送通道,只能被動接受資訊了;
      • 被動方: 收到通道關閉的資訊;
      • 被動方: 我現在也關閉了向你那邊傳送資訊的通道
      • 主動方: 左後收到資訊,連線斷開,之後雙方無法通訊
  5. TCP/IP的併發限制:

    • 瀏覽器對同一個域名下併發的TCP連線是有限制的(2-10個不等)
    • 而且在http1.0中往往一個資源的下載就需要一個tcp/ip請求

2. 瀏覽器機制

(1)程式和執行緒的概念

  1. 程式是CPU資源分配的最小單位,是能擁有資源和獨立執行的最小單位;
  2. 執行緒是CPU排程的最小單位,執行緒是建立在程式的基礎上的一次程式執行單位,一個程式可以擁有多個執行緒;
  3. 通俗的講:程式是一個工廠,工廠有它獨立的資源,工廠之間相互獨立->程式之間相互獨立,執行緒是工廠中的工人,多個工人之間可以協作完成任務,工廠內有一個或多個工人,工人之間共享空間。

(2)多程式的瀏覽器

瀏覽器是多程式的,有一個主控程式,以及每一個tab頁面都會開一個程式(某些情況下多個tab由於優化策略會合並)

  • 瀏覽器主要程式:
  1. Browser程式:瀏覽器的主程式,負責協調、主控,只有一個,作用:

    • 負責瀏覽器介面的顯示、與使用者互動(如前進、後退等)
    • 負責各個頁面的管理,建立和銷燬其他程式;
    • 將Renderer程式得到的記憶體中的Bitmap繪製到使用者介面上
    • 網路資源的管理和下載等
  2. 第三方外掛程式: 每種型別的外掛對應一個程式,僅當該外掛使用時才建立;
  3. GPU程式: 最多一個,用於3D繪製等;
  4. 瀏覽器渲染程式(Renderer程式、瀏覽器核心、內部是多執行緒)

    • 預設沒開啟一個tab頁面,就會啟動一個Renderer程式;
    • 負責頁面的渲染,指令碼的執行,事件的處理。
  • 瀏覽器多程式的優勢

    1. 避免單個page crash影響整個瀏覽器;
    2. 避免第三方外掛crash影響整個瀏覽器
    3. 多程式充分利用多核優勢;
    4. 方便使用沙盒模型隔離外掛等程式,提高瀏覽器穩定性

簡單點理解:如果瀏覽器是單程式,那麼某個tab頁或第三方外掛崩潰了,就會導致整個瀏覽器崩潰,體驗度極差,不過多程式記憶體消耗會更大,有點用空間換時間。

瀏覽器核心(渲染程式)

  • 瀏覽器渲染程式內部是多執行緒,包含主要執行緒有:

1.GUI渲染執行緒:

  • (1)負責瀏覽器介面的渲染,解析HTML、CSS,構建DOM樹和RenderObject樹,佈局和繪製等;
  • (2) 當介面需要重繪(Repaint)或由於某種操作引發迴流(reflow)時該執行緒會執行;
  • 注意:GUI渲染執行緒和JS引擎執行緒是互斥的,當JS引擎執行時GUI執行緒會被掛起,GUI更新會儲存在一個佇列中等JS引擎空閒時立即執行。

2.JS引擎執行緒:

  • JS核心,負責處理JavaScript指令碼程式(V8引擎)
  • 負責解析JavaScript指令碼,執行程式碼;
  • JS引擎一直等待著任務佇列中的任務到來,然後加以處理,一個tab頁面(renderer程式)中無論什麼時候都只有一個JS執行緒在執行JS程式;
  • 注意:由於GUI渲染執行緒和JS引擎執行緒是互斥的,所以如果JS程式執行時間過長,這樣會導致頁面渲染不連貫,導致頁面渲染載入阻塞;

3.事件觸發執行緒:

  • 歸屬於瀏覽器,而不是JS引擎,用來控制事件迴圈;
  • 當JS引擎執行程式碼塊如setTimeOut時(也可以來自瀏覽器核心的其他執行緒,如滑鼠單擊事件、AJAX非同步請求等),會將對應的任務新增到事件執行緒中;
  • 當對應的事件符合觸發條件被觸發時,該執行緒就會把事件新增到JS的待處理佇列的隊尾,等待JS引擎的處理;
  • 注意:由於JS的單執行緒的關係所以這些待處理佇列中的事件都得排隊等待JS引擎處理(當JS引擎空閒時才會去執行)。

4.定時觸發器執行緒:

  • setTimeOut與setInterval所在的執行緒;
  • 瀏覽器的定時計數器並不是由JavaScript引擎計數的,(因為JavaScript是單執行緒,如果處於阻塞狀態就會影響計時的準確)因此通過單獨的執行緒來計時並觸發定時(計時完畢後,新增到事件佇列,等待JS引擎空閒時執行)

5.非同步http請求執行緒:

  • 在XMLHttpRequest在連線後是通過瀏覽器新開一個執行緒請求的
  • 將檢測到狀態變更時,如果設定有回撥函式,非同步執行緒就將產生狀態變更事件,將這個回撥在放到事件佇列中,再由JavaScript引擎執行。

一、 一個頁面從輸入URL到載入顯示完成,這個過程發生了什麼?

  • 簡潔版:

    • 瀏覽器根據請求的URL交給DNS域名解析,找到真實的IP,向伺服器發起請求;
    • 伺服器交給後臺處理完成後返回資料,瀏覽器接收檔案(HTML、CSS、JavaScript等);
    • 瀏覽器對載入到的資源(HTML、CSS、JavaScript等)進行語法解析,構建相應的內部資料結構(DOM樹、CSS樹、render樹等);
    • 載入解析到的資原始檔、渲染頁面、完成。
  • 詳細版:

    1. 首先瀏覽器開啟一個執行緒來處理這個請求,對URL分析判斷,如果是http協議就按照Web方式來處理;
    2. 其次瀏覽器會對URL進行解析,一般包括(協議頭、主機域名或IP地址、埠號、請求路徑、查詢引數、hash等),然後開啟網路執行緒發出一個完整到http請求;
    3. 當然一般我們輸入的URL是伺服器域名,這時就需要DNS通過域名查詢得到對應的IP;
    4. DNS首先會檢視瀏覽器DNS快取,沒有就查詢計算機本地DNS快取,還沒有就詢問遞迴式DNS伺服器(即網路提供商,一般這個伺服器都會有自己的快取,所以IP查詢一般在這裡完成),如果沒有快取,那就需要通過根域名和TLD域名伺服器指到對應的權威DNS伺服器找回記錄,並快取到遞迴式伺服器,然後遞迴伺服器在將記錄返回給本地。
    5. 有了IP地址,此時網路層便會通過IP地址尋的對應伺服器的實體地址
    6. 尋得伺服器地址,客戶端在網路傳輸層便可以和伺服器通過三次握手建立tcpip連線
    7. 連線建立後網路資料鏈路層將資料包裝成幀;
    8. 最後物理層利用物理介質進行傳輸;
    9. 到了伺服器,就會通過相反的方式將資料一層一層的還原回去;
    10. 請求到了後臺伺服器,一般會有統一的驗證,如安全驗證、跨域驗證等,驗證未通過就直接返回相應的http報文
    11. 驗證通過後,就會進入後臺程式碼,此時程式收到請求,然後執行對應的操作(如查詢資料庫等);
    12. 如果瀏覽器訪問過,且快取上有對應的資源,便會與伺服器最後修改時間對比,一致便返回304,告訴瀏覽器可使用本地快取;
    13. 前端瀏覽器接收到響應成功的報文後便開始下載網頁
    14. 下載完的網頁將被交給瀏覽器核心(渲染程式)進行處理:

      1. 根據頂部定義的DTD型別進行對應的解析方式;
      2. 渲染程式內部是多執行緒的,網頁的解析將會被交給內部的GUI渲染執行緒處理;
      3. 首先渲染執行緒中的HTML直譯器,將HTML網頁和資源從位元組流解釋轉換成字元流;
      4. 再通過詞法分析器將字元流解釋成詞語;
      5. 之後經過語法分析器根據詞語構建成節點;最後通過這些節點組建一個DOM樹;
      6. 這個過程中,如果遇到的DOM節點是JavaScript程式碼,就會呼叫JavaScript引擎對JavaScript程式碼進行解釋執行,此時由JavaScript引擎和GUI渲染執行緒的互斥,GUI渲染執行緒就會被掛起,渲染過程停止;如果JavaScript程式碼的執行中對DOM樹進行了修改,那麼DOM的構建需要從新開始;
      7. 如果節點需要依賴其他資源,如(圖片,CSS等),便會呼叫網路模組的資源載入器來載入它們,但它們是非同步的,不會阻塞當前DOM樹的構建;
      8. 如果遇到的是JavaScript資源URL(沒有標記非同步),則需要停止當前DOM的構建,直到JavaScript的資源載入並被JavaScript引擎執行後才繼續構建DOM;
      9. 對於CSS,CSS直譯器會將CSS檔案解釋成內部表示結構,生成CSS規則樹;
      10. 然後合併CSS規則樹和DOM樹,生成render渲染樹;
      11. 最後對render樹進行佈局和繪製,並將結果通過IO執行緒傳遞給Browser控制程式進行顯示。

相關文章