面試詳解:在瀏覽器輸入URL回車以後發生了什麼?(超詳細版)

這篇文章專治面試中:"在瀏覽器輸入URL回車以後發生了什麼?"、"瀏覽器輸入URL發送的一系列操做!"等面試問題。 css

\color{red}{前言}

這個問題已是老生常談了,更是常常被做爲面試的壓軸題出現,網上也有不少文章,但最近閒的無聊,而後就本身作了一篇筆記,感受比以前理解更透徹了。html

這篇筆記是我這兩天看了數十篇文章總結出來的,因此相對全面一點,但因爲我是作前端的,因此會比較重點分析瀏覽器渲染頁面那一部分,至於其餘部分我會羅列出關鍵詞,感興趣的能夠自行查閱,前端

\color{red}{注意}

本文的步驟是創建在,請求的是一個簡單的 HTTP 請求,沒有 HTTPS、HTTP二、最簡單的 DNS、沒有代理、而且服務器沒有任何問題的基礎上,儘管這是不切實際的。html5

\color{red}{大體流程}

  • URL 解析
  • DNS 查詢
  • TCP 鏈接
  • 處理請求
  • 接受響應
  • 渲染頁面

1、URL 解析

\color{red}{地址解析}

首先判斷你輸入的是一個合法的 URL 仍是一個待搜索的關鍵詞,而且根據你輸入的內容進行自動完成、字符編碼等操做。git

\color{red}{HSTS}

因爲安全隱患,會使用 HSTS 強制客戶端使用 HTTPS 訪問頁面。詳見:你所不知道的 HSTSgithub

\color{red}{其餘操做}

瀏覽器還會進行一些額外的操做,好比安全檢查、訪問限制(以前國產瀏覽器限制 996.icu)。面試

\color{red}{檢查緩存}

2、DNS 查詢

\color{red}{基本步驟}

1. 瀏覽器緩存

先檢查瀏覽器中是否有存在緩存,沒有則調用系統庫函數進行查詢。瀏覽器

2. 操做系統緩存

操做系統也有本身的 DNS緩存,但在這以前,會向檢查域名是否存在本地的 Hosts 文件裏,沒有則向 DNS 服務器發送查詢請求。緩存

3. 路由器緩存

路由器也有本身的緩存。安全

4. ISP DNS 緩存

ISP DNS(因特網服務提供商) 就是在客戶端電腦上設置的首選 DNS 服務器,它們在大多數狀況下都會有緩存。

5. 根域名服務器查詢

在前面全部步驟沒有緩存的狀況下,本地 DNS 服務器會將請求轉發到互聯網上的根域,下面這個圖很好的詮釋了整個流程:

須要注意的點

  1. 遞歸方式:一路查下去中間不返回,獲得最終結果才返回信息(瀏覽器到本地DNS服務器的過程)
  2. 迭代方式,就是本地DNS服務器到根域名服務器查詢的方式。
  3. 什麼是 DNS 劫持
  4. 前端 dns-prefetch 優化

3、TCP 鏈接

TCP/IP 分爲四層,在發送數據時,每層都要對數據進行封裝:

1. 應用層:發送 HTTP 請求

在前面的步驟咱們已經獲得服務器的 IP 地址,瀏覽器會開始構造一個 HTTP 報文,其中包括:

  • 請求報頭(Request Header):請求方法、目標地址、遵循的協議等等
  • 請求主體(其餘參數)

其中須要注意的點:

  • 瀏覽器只能發送 GET、POST 方法,而打開網頁使用的是 GET 方法

2. 傳輸層:TCP 傳輸報文

傳輸層會發起一條到達服務器的 TCP 鏈接,爲了方便傳輸,會對數據進行分割(以報文段爲單位),並標記編號,方便服務器接受時可以準確地還原報文信息。

在創建鏈接前,會先進行 TCP 三次握手。關於 TCP/IP 三次握手,網上已經有不少段子和圖片生動地描述了。

3. 網絡層:IP協議查詢Mac地址

將數據段打包,並加入源及目標的IP地址,而且負責尋找傳輸路線。

判斷目標地址是否與當前地址處於同一網絡中,是的話直接根據 Mac 地址發送,不然使用路由表查找下一跳地址,以及使用 ARP 協議查詢它的 Mac 地址。

注意:在 OSI 參考模型中 ARP 協議位於鏈路層,但在 TCP/IP 中,它位於網絡層。

4. 鏈路層:以太網協議

以太網協議

根據以太網協議將數據分爲以「幀」爲單位的數據包,每一幀分爲兩個部分:

  • 標頭:數據包的發送者、接受者、數據類型
  • 數據:數據包具體內容

Mac 地址

以太網規定了連入網絡的全部設備都必須具有「網卡」接口,數據包都是從一塊網卡傳遞到另外一塊網卡,網卡的地址就是 Mac 地址。每個 Mac 地址都是獨一無二的,具有了一對一的能力。

廣播

發送數據的方法很原始,直接把數據經過 ARP 協議,向本網絡的全部機器發送,接收方根據標頭信息與自身 Mac 地址比較,一致就接受,不然丟棄。

注意: 接收方迴應是單播。

相關知識點: ARP 攻擊

服務器接受請求 接受過程就是把以上步驟逆轉過來,參見上圖。

4、服務器處理請求

大體流程

HTTPD

最多見的 HTTPD 有 Linux 上經常使用的 Apache 和 Nginx,以及 Windows 上的 IIS。

它會監聽獲得的請求,而後開啓一個子進程去處理這個請求。

處理請求

接受 TCP 報文後,會對鏈接進行處理,對HTTP協議進行解析(請求方法、域名、路徑等),而且進行一些驗證:

  • 驗證是否配置虛擬主機
  • 驗證虛擬主機是否接受此方法
  • 驗證該用戶可使用該方法(根據 IP 地址、身份信息等)

重定向

假如服務器配置了 HTTP 重定向,就會返回一個 301永久重定向響應,瀏覽器就會根據響應,從新發送 HTTP 請求(從新執行上面的過程)。

關於更多:詳見這篇文章

URL 重寫

而後會查看 URL 重寫規則,若是請求的文件是真實存在的,好比圖片、html、css、js文件等,則會直接把這個文件返回。

不然服務器會按照規則把請求重寫到 一個 REST 風格的 URL 上。

而後根據動態語言的腳本,來決定調用什麼類型的動態文件解釋器來處理這個請求。

以 PHP 語言的 MVC 框架舉例,它首先會初始化一些環境的參數,根據 URL 由上到下地去匹配路由,而後讓路由所定義的方法去處理請求。

5、瀏覽器接受響應

瀏覽器接收到來自服務器的響應資源後,會對資源進行分析。

首先查看 Response header,根據不一樣狀態碼作不一樣的事(好比上面提到的重定向)。

若是響應資源進行了壓縮(好比 gzip),還須要進行解壓。

而後,對響應資源作緩存。

接下來,根據響應資源裏的 MIME 類型去解析響應內容(好比 HTML、Image各有不一樣的解析方式)。

6、渲染頁面

瀏覽器內核

不一樣的瀏覽器內核,渲染過程也不徹底相同,但大體流程都差很少。

基本流程

1.HTML 解析

首先要知道瀏覽器解析是從上往下一行一行地解析的。

解析的過程能夠分爲四個步驟:

1.解碼(encoding)

傳輸回來的其實都是一些二進制字節數據,瀏覽器須要根據文件指定編碼(例如UTF-8)轉換成字符串,也就是HTML 代碼。

2.預解析(pre-parsing)

預解析作的事情是提早加載資源,減小處理時間,它會識別一些會請求資源的屬性,好比img標籤的src屬性,並將這個請求加到請求隊列中。

3.符號化(Tokenization)

符號化是詞法分析的過程,將輸入解析成符號,HTML 符號包括,開始標籤、結束標籤、屬性名和屬性值。

它經過一個狀態機去識別符號的狀態,好比遇到<,>狀態都會產生變化。

4.構建樹(tree construction)

注意:符號化和構建樹是並行操做的,也就是說只要解析到一個開始標籤,就會建立一個 DOM 節點。

在上一步符號化中,解析器得到這些標記,而後以合適的方法建立DOM對象並把這些符號插入到DOM對象中。

<html>
<head>
    <title>Web page parsing</title>
</head>
<body>
    <div>
        <h1>Web page parsing</h1>
        <p>This is an example Web page.</p>
    </div>
</body>
</html>

複製代碼

瀏覽器容錯進制

你歷來沒有在瀏覽器看過相似」語法無效」的錯誤,這是由於瀏覽器去糾正錯誤的語法,而後繼續工做。

事件

當整個解析的過程完成之後,瀏覽器會經過DOMContentLoaded事件來通知DOM解析完成。

2.CSS 解析

一旦瀏覽器下載了 CSS,CSS 解析器就會處理它遇到的任何 CSS,根據語法規範解析出全部的 CSS 並進行標記化,而後咱們獲得一個規則表。

CSS 匹配規則

在匹配一個節點對應的 CSS 規則時,是按照從右到左的順序的,例如:div p { font-size :14px }會先尋找全部的p標籤而後判斷它的父元素是否爲div。

因此咱們寫 CSS 時,儘可能用 id 和 class,千萬不要過分層疊。

3.渲染樹

其實這就是一個 DOM 樹和 CSS 規則樹合併的過程。

注意:渲染樹會忽略那些不須要渲染的節點,好比設置了display:none的節點。

計算

經過計算讓任何尺寸值都減小到三個可能之一:auto、百分比、px,好比把rem轉化爲px。

級聯

瀏覽器須要一種方法來肯定哪些樣式才真正須要應用到對應元素,因此它使用一個叫作specificity的公式,這個公式會經過:

  • 標籤名、class、id
  • 是否內聯樣式
  • !important

而後得出一個權重值,取最高的那個。

渲染阻塞

當遇到一個script標籤時,DOM 構建會被暫停,直至腳本完成執行,而後繼續構建 DOM 樹。

但若是 JS 依賴 CSS 樣式,而它尚未被下載和構建時,瀏覽器就會延遲腳本執行,直至 CSS Rules 被構建。

全部咱們知道:

  • CSS 會阻塞 JS 執行
  • JS 會阻塞後面的 DOM 解析

爲了不這種狀況,應該如下原則:

  • CSS 資源排在 JavaScript 資源前面
  • JS 放在 HTML 最底部,也就是 前

另外,若是要改變阻塞模式,可使用 defer 與 async,詳見:這篇文章

4.佈局與繪製

肯定渲染樹種全部節點的幾何屬性,好比:位置、大小等等,最後輸入一個盒子模型,它能精準地捕獲到每一個元素在屏幕內的準確位置與大小。

而後遍歷渲染樹,調用渲染器的 paint() 方法在屏幕上顯示其內容。

5.合併渲染層

把以上繪製的全部圖片合併,最終輸出一張圖片。

6. 迴流與重繪

迴流(reflow)

當瀏覽器發現某個部分發現變化影響了佈局時,須要倒回去從新渲染,會從html標籤開始遞歸往下,從新計算位置和大小。

reflow基本是沒法避免的,由於當你滑動一下鼠標、resize 窗口,頁面就會產生變化。

重繪(repaint)

改變了某個元素的背景色、文字顏色等等不會影響周圍元素的位置變化時,就會發生重繪。

每次重繪後,瀏覽器還須要合併渲染層並輸出到屏幕上。

迴流的成本要比重繪高不少,因此咱們應該儘可能避免產生迴流。

好比:

display:none 會觸發迴流,而 visibility:hidden 只會觸發重繪。

7. JavaScript 編譯執行

大體流程

能夠分爲三個階段:

1.詞法分析

JS 腳本加載完畢後,會首先進入語法分析階段,它首先會分析代碼塊的語法是否正確,不正確則拋出「語法錯誤」,中止執行。

幾個步驟:

  • 分詞,例如將var a = 2,,分紅var、a、=、2這樣的詞法單元。
  • 解析,將詞法單元轉換成抽象語法樹(AST)。
  • 代碼生成,將抽象語法樹轉換成機器指令。

2. 預編譯

JS 有三種運行環境:

  • 全局環境
  • 函數環境
  • eval

每進入一個不一樣的運行環境都會建立一個對應的執行上下文,根據不一樣的上下文環境,造成一個函數調用棧,棧底永遠是全局執行上下文,棧頂則永遠是當前執行上下文。

建立執行上下文

建立執行上下文的過程當中,主要作了如下三件事:

  • 建立變量對象:參數、函數、變量
  • 創建做用域鏈:確認當前執行環境是否能訪問變量
  • 肯定 This 指向

3. 執行

JS 線程

雖然 JS 是單線程的,但實際上參與工做的線程一共有四個:

其中三個只是協助,只有 JS 引擎線程是真正執行的

  • JS 引擎線程:也叫 JS 內核,負責解析執行 JS 腳本程序的主線程,例如 V8 引擎
  • 事件觸發線程:屬於瀏覽器內核線程,主要用於控制事件,例如鼠標、鍵盤等,當事件被觸發時,就會把事件的處理函數推動事件隊列,等待 JS 引擎線程執行
  • 定時器觸發線程:主要控制setInterval和setTimeout,用來計時,計時完畢後,則把定時器的處理函數推動事件隊列中,等待 JS 引擎線程。
  • HTTP 異步請求線程:經過XMLHttpRequest鏈接後,經過瀏覽器新開的一個線程,監控readyState狀態變動時,若是設置了該狀態的回調函數,則將該狀態的處理函數推動事件隊列中,等待JS引擎線程執行。

注:瀏覽器對同一域名的併發鏈接數是有限的,一般爲 6 個。

宏任務

分爲:

  • 同步任務:按照順序執行,只有前一個任務完成後,才能執行後一個任務
  • 異步任務:不直接執行,只有知足觸發條件時,相關的線程將該異步任務推動任務隊列中,等待JS引擎主線程上的任務執行完畢時纔開始執行,例如異步Ajax、DOM事件,setTimeout等。

微任務

微任務是ES6和Node環境下的,主要 API 有:Promise,process.nextTick。

微任務的執行在宏任務的同步任務以後,在異步任務以前。

代碼例子

console.log('1'); // 宏任務 同步

setTimeout(function() {
    console.log('2'); // 宏任務 異步
})

new Promise(function(resolve) {
    console.log('3'); // 宏任務 同步
    resolve();
}).then(function() {
    console.log('4') // 微任務
})

console.log('5') // 宏任務 同步
以上代碼輸出順序爲:1,3,5,4,2
複製代碼

參考文檔

本文做者:4Ark

本文連接: 4ark.me/post/b6c7c0…

版權: 本站文章均採用 CC BY-NC-SA 3.0 CN 許可協議,請勿用於商業,轉載註明出處!

相關文章
相關標籤/搜索