<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          在瀏覽器輸入xxxhub 回車之后發(fā)生了什么?(超詳細版)

          共 6173字,需瀏覽 13分鐘

           ·

          2020-12-30 20:21

          點擊“開發(fā)者技術(shù)前線”,選擇“星標?”

          讓一部分開發(fā)者看到未來

          https://4ark.me/post/b6c7c0a2.html

          前言

          這個問題已經(jīng)是老生常談了,更是經(jīng)常被作為面試的壓軸題出現(xiàn),網(wǎng)上也有很多文章,但最近閑的無聊,然后就自己做了一篇筆記,感覺比之前理解更透徹了。

          篇筆記是我這兩天看了數(shù)十篇文章總結(jié)出來的,所以相對全面一點,但由于我是做前端的,所以會比較重點分析瀏覽器渲染頁面那一部分,至于其他部分我會羅列出關(guān)鍵詞,感興趣的可以自行查閱.
          注意:本文的步驟是建立在,請求的是一個簡單的 HTTP 請求,沒有 HTTPS、HTTP2、最簡單的 DNS、沒有代理、并且服務(wù)器沒有任何問題的基礎(chǔ)上,盡管這是不切實際的。

          大致流程

          1. URL 解析

          2. DNS 查詢

          3. TCP 連接

          4. 處理請求

          5. 接受響應(yīng)

          6. 渲染頁面

          一、URL 解析

          地址解析:

          首先判斷你輸入的是一個合法的 URL 還是一個待搜索的關(guān)鍵詞,并且根據(jù)你輸入的內(nèi)容進行自動完成、字符編碼等操作。

          HSTS

          由于安全隱患,會使用 HSTS 強制客戶端使用 HTTPS 訪問頁面。詳見:你所不知道的 HSTS[1]。

          其他操作

          瀏覽器還會進行一些額外的操作,比如安全檢查、訪問限制(之前國產(chǎn)瀏覽器限制 996.icu)。

          檢查緩存

          二、DNS 查詢

          基本步驟

          1. 瀏覽器緩存

          瀏覽器會先檢查是否在緩存中,沒有則調(diào)用系統(tǒng)庫函數(shù)進行查詢。

          2. 操作系統(tǒng)緩存

          操作系統(tǒng)也有自己的 DNS緩存,但在這之前,會向檢查域名是否存在本地的 Hosts 文件里,沒有則向 DNS 服務(wù)器發(fā)送查詢請求。

          3. 路由器緩存

          路由器也有自己的緩存。

          4. ISP DNS 緩存

          ISP DNS 就是在客戶端電腦上設(shè)置的首選 DNS 服務(wù)器,它們在大多數(shù)情況下都會有緩存。

          根域名服務(wù)器查詢

          在前面所有步驟沒有緩存的情況下,本地 DNS 服務(wù)器會將請求轉(zhuǎn)發(fā)到互聯(lián)網(wǎng)上的根域,下面這個圖很好的詮釋了整個流程:

          根域名服務(wù)器(維基百科)

          需要注意的點

          1. 遞歸方式:一路查下去中間不返回,得到最終結(jié)果才返回信息(瀏覽器到本地DNS服務(wù)器的過程)

          2. 迭代方式,就是本地DNS服務(wù)器到根域名服務(wù)器查詢的方式。

          3. 什么是 DNS 劫持

          4. 前端 dns-prefetch 優(yōu)化

          三、TCP 連接

          TCP/IP 分為四層,在發(fā)送數(shù)據(jù)時,每層都要對數(shù)據(jù)進行封裝:

          1. 應(yīng)用層:發(fā)送 HTTP 請求

          在前面的步驟我們已經(jīng)得到服務(wù)器的 IP 地址,瀏覽器會開始構(gòu)造一個 HTTP 報文,其中包括:

          • 請求報頭(Request Header):請求方法、目標地址、遵循的協(xié)議等等

          • 請求主體(其他參數(shù))

          其中需要注意的點:

          • 瀏覽器只能發(fā)送 GET、POST 方法,而打開網(wǎng)頁使用的是 GET 方法

          2. 傳輸層:TCP 傳輸報文

          傳輸層會發(fā)起一條到達服務(wù)器的 TCP 連接,為了方便傳輸,會對數(shù)據(jù)進行分割(以報文段為單位),并標記編號,方便服務(wù)器接受時能夠準確地還原報文信息。

          在建立連接前,會先進行 TCP 三次握手。

          關(guān)于 TCP/IP 三次握手,網(wǎng)上已經(jīng)有很多段子和圖片生動地描述了。

          相關(guān)知識點:

          1. SYN 泛洪攻擊

          3. 網(wǎng)絡(luò)層:IP協(xié)議查詢Mac地址

          將數(shù)據(jù)段打包,并加入源及目標的IP地址,并且負責尋找傳輸路線。

          判斷目標地址是否與當前地址處于同一網(wǎng)絡(luò)中,是的話直接根據(jù) Mac 地址發(fā)送,否則使用路由表查找下一跳地址,以及使用 ARP 協(xié)議查詢它的 Mac 地址。

          注意:在 OSI 參考模型中 ARP 協(xié)議位于鏈路層,但在 TCP/IP 中,它位于網(wǎng)絡(luò)層。

          4. 鏈路層:以太網(wǎng)協(xié)議

          以太網(wǎng)協(xié)議

          根據(jù)以太網(wǎng)協(xié)議將數(shù)據(jù)分為以“幀”為單位的數(shù)據(jù)包,每一幀分為兩個部分:

          • 標頭:數(shù)據(jù)包的發(fā)送者、接受者、數(shù)據(jù)類型

          • 數(shù)據(jù):數(shù)據(jù)包具體內(nèi)容

          Mac 地址

          以太網(wǎng)規(guī)定了連入網(wǎng)絡(luò)的所有設(shè)備都必須具備“網(wǎng)卡”接口,數(shù)據(jù)包都是從一塊網(wǎng)卡傳遞到另一塊網(wǎng)卡,網(wǎng)卡的地址就是 Mac 地址。每一個 Mac 地址都是獨一無二的,具備了一對一的能力。

          廣播

          發(fā)送數(shù)據(jù)的方法很原始,直接把數(shù)據(jù)通過 ARP 協(xié)議,向本網(wǎng)絡(luò)的所有機器發(fā)送,接收方根據(jù)標頭信息與自身 Mac 地址比較,一致就接受,否則丟棄。

          注意:接收方回應(yīng)是單播。

          相關(guān)知識點:

          1. ARP 攻擊

          服務(wù)器接受請求

          接受過程就是把以上步驟逆轉(zhuǎn)過來,參見上圖。

          四、服務(wù)器處理請求

          大致流程

          HTTPD

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

          它會監(jiān)聽得到的請求,然后開啟一個子進程去處理這個請求。

          處理請求

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

          • 驗證是否配置虛擬主機

          • 驗證虛擬主機是否接受此方法

          • 驗證該用戶可以使用該方法(根據(jù) IP 地址、身份信息等)

          重定向

          假如服務(wù)器配置了 HTTP 重定向,就會返回一個?301永久重定向響應(yīng),瀏覽器就會根據(jù)響應(yīng),重新發(fā)送 HTTP 請求(重新執(zhí)行上面的過程)。

          關(guān)于更多:詳見這篇文章[2]

          URL 重寫

          然后會查看 URL 重寫規(guī)則,如果請求的文件是真實存在的,比如圖片、html、css、js文件等,則會直接把這個文件返回。

          否則服務(wù)器會按照規(guī)則把請求重寫到 一個 REST 風格的 URL 上。

          然后根據(jù)動態(tài)語言的腳本,來決定調(diào)用什么類型的動態(tài)文件解釋器來處理這個請求。

          以 PHP 語言的 MVC 框架舉例,它首先會初始化一些環(huán)境的參數(shù),根據(jù) URL 由上到下地去匹配路由,然后讓路由所定義的方法去處理請求。

          五、瀏覽器接受響應(yīng)

          瀏覽器接收到來自服務(wù)器的響應(yīng)資源后,會對資源進行分析。

          首先查看 Response header,根據(jù)不同狀態(tài)碼做不同的事(比如上面提到的重定向)。

          如果響應(yīng)資源進行了壓縮(比如 gzip),還需要進行解壓。

          然后,對響應(yīng)資源做緩存。

          接下來,根據(jù)響應(yīng)資源里的?MIME[3]?類型去解析響應(yīng)內(nèi)容(比如 HTML、Image各有不同的解析方式)。

          六、渲染頁面

          瀏覽器內(nèi)核

          不同的瀏覽器內(nèi)核,渲染過程也不完全相同,但大致流程都差不多。

          基本流程

          6.1. HTML 解析

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

          解析的過程可以分為四個步驟:

          ① 解碼(encoding)

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

          ② 預解析(pre-parsing)

          預解析做的事情是提前加載資源,減少處理時間,它會識別一些會請求資源的屬性,比如img標簽的src屬性,并將這個請求加到請求隊列中。

          ③ 符號化(Tokenization)

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

          它通過一個狀態(tài)機去識別符號的狀態(tài),比如遇到<,>狀態(tài)都會產(chǎn)生變化。

          ④ 構(gòu)建樹(tree construction)

          注意:符號化和構(gòu)建樹是并行操作的,也就是說只要解析到一個開始標簽,就會創(chuàng)建一個 DOM 節(jié)點。

          在上一步符號化中,解析器獲得這些標記,然后以合適的方法創(chuàng)建DOM對象并把這些符號插入到DOM對象中。

              Web page parsing    

          Web page parsing

          This is an example Web page.

          瀏覽器容錯進制

          你從來沒有在瀏覽器看過類似”語法無效”的錯誤,這是因為瀏覽器去糾正錯誤的語法,然后繼續(xù)工作。

          事件

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

          6.2. CSS 解析

          一旦瀏覽器下載了 CSS,CSS 解析器就會處理它遇到的任何 CSS,根據(jù)語法規(guī)范[4]解析出所有的 CSS 并進行標記化,然后我們得到一個規(guī)則表。

          CSS 匹配規(guī)則

          在匹配一個節(jié)點對應(yīng)的 CSS 規(guī)則時,是按照從右到左的順序的,例如:div p { font-size :14px }會先尋找所有的p標簽然后判斷它的父元素是否為div。

          所以我們寫 CSS 時,盡量用 id 和 class,千萬不要過度層疊。

          6.3. 渲染樹

          其實這就是一個 DOM 樹和 CSS 規(guī)則樹合并的過程。

          注意:渲染樹會忽略那些不需要渲染的節(jié)點,比如設(shè)置了display:none的節(jié)點。

          計算

          通過計算讓任何尺寸值都減少到三個可能之一:auto、百分比、px,比如把rem轉(zhuǎn)化為px。

          級聯(lián)

          瀏覽器需要一種方法來確定哪些樣式才真正需要應(yīng)用到對應(yīng)元素,所以它使用一個叫做specificity的公式,這個公式會通過:

          1. 標簽名、class、id

          2. 是否內(nèi)聯(lián)樣式

          3. !important

          然后得出一個權(quán)重值,取最高的那個。

          渲染阻塞

          當遇到一個script標簽時,DOM 構(gòu)建會被暫停,直至腳本完成執(zhí)行,然后繼續(xù)構(gòu)建 DOM 樹。

          但如果 JS 依賴 CSS 樣式,而它還沒有被下載和構(gòu)建時,瀏覽器就會延遲腳本執(zhí)行,直至 CSS Rules 被構(gòu)建。

          所有我們知道:

          • CSS 會阻塞 JS 執(zhí)行

          • JS 會阻塞后面的 DOM 解析

          為了避免這種情況,應(yīng)該以下原則:

          • CSS 資源排在 JavaScript 資源前面

          • JS 放在 HTML 最底部,也就是?

          另外,如果要改變阻塞模式,可以使用 defer 與 async,詳見:這篇文章[5]

          6.4. 布局與繪制

          確定渲染樹種所有節(jié)點的幾何屬性,比如:位置、大小等等,最后輸入一個盒子模型,它能精準地捕獲到每個元素在屏幕內(nèi)的準確位置與大小。

          然后遍歷渲染樹,調(diào)用渲染器的 paint() 方法在屏幕上顯示其內(nèi)容。

          6.5. 合并渲染層

          把以上繪制的所有圖片合并,最終輸出一張圖片。

          6.6. 回流與重繪

          回流(reflow)

          當瀏覽器發(fā)現(xiàn)某個部分發(fā)現(xiàn)變化影響了布局時,需要倒回去重新渲染,會從html標簽開始遞歸往下,重新計算位置和大小。

          reflow基本是無法避免的,因為當你滑動一下鼠標、resize 窗口,頁面就會產(chǎn)生變化。

          重繪(repaint)

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

          每次重繪后,瀏覽器還需要合并渲染層并輸出到屏幕上。

          回流的成本要比重繪高很多,所以我們應(yīng)該盡量避免產(chǎn)生回流。

          比如:

          • display:none?會觸發(fā)回流,而?visibility:hidden?只會觸發(fā)重繪。

          6.7. JavaScript 編譯執(zhí)行

          大致流程

          可以分為三個階段:

          1. 詞法分析

          JS 腳本加載完畢后,會首先進入語法分析階段,它首先會分析代碼塊的語法是否正確,不正確則拋出“語法錯誤”,停止執(zhí)行。

          幾個步驟:

          • 分詞,例如將var a = 2,,分成var、a、=、2這樣的詞法單元。

          • 解析,將詞法單元轉(zhuǎn)換成抽象語法樹(AST)。

          • 代碼生成,將抽象語法樹轉(zhuǎn)換成機器指令。

          2. 預編譯

          JS 有三種運行環(huán)境:

          • 全局環(huán)境

          • 函數(shù)環(huán)境

          • eval

          每進入一個不同的運行環(huán)境都會創(chuàng)建一個對應(yīng)的執(zhí)行上下文,根據(jù)不同的上下文環(huán)境,形成一個函數(shù)調(diào)用棧,棧底永遠是全局執(zhí)行上下文,棧頂則永遠是當前執(zhí)行上下文。

          創(chuàng)建執(zhí)行上下文

          創(chuàng)建執(zhí)行上下文的過程中,主要做了以下三件事:

          • 創(chuàng)建變量對象

            • 參數(shù)、函數(shù)、變量

          • 建立作用域鏈

            • 確認當前執(zhí)行環(huán)境是否能訪問變量

          • 確定 This 指向

          3. 執(zhí)行

          JS 線程

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

          其中三個只是協(xié)助,只有 JS 引擎線程是真正執(zhí)行的

          • JS 引擎線程:也叫 JS 內(nèi)核,負責解析執(zhí)行 JS 腳本程序的主線程,例如 V8 引擎

          • 事件觸發(fā)線程:屬于瀏覽器內(nèi)核線程,主要用于控制事件,例如鼠標、鍵盤等,當事件被觸發(fā)時,就會把事件的處理函數(shù)推進事件隊列,等待 JS 引擎線程執(zhí)行

          • 定時器觸發(fā)線程:主要控制setIntervalsetTimeout,用來計時,計時完畢后,則把定時器的處理函數(shù)推進事件隊列中,等待 JS 引擎線程。

          • HTTP 異步請求線程:通過XMLHttpRequest連接后,通過瀏覽器新開的一個線程,監(jiān)控readyState狀態(tài)變更時,如果設(shè)置了該狀態(tài)的回調(diào)函數(shù),則將該狀態(tài)的處理函數(shù)推進事件隊列中,等待JS引擎線程執(zhí)行。

          注:瀏覽器對同一域名的并發(fā)連接數(shù)是有限的,通常為 6 個。

          宏任務(wù)

          分為:

          • 同步任務(wù):按照順序執(zhí)行,只有前一個任務(wù)完成后,才能執(zhí)行后一個任務(wù)

          • 異步任務(wù):不直接執(zhí)行,只有滿足觸發(fā)條件時,相關(guān)的線程將該異步任務(wù)推進任務(wù)隊列中,等待JS引擎主線程上的任務(wù)執(zhí)行完畢時才開始執(zhí)行,例如異步Ajax、DOM事件,setTimeout等。

          微任務(wù)

          微任務(wù)是ES6和Node環(huán)境下的,主要 API 有:Promiseprocess.nextTick。

          微任務(wù)的執(zhí)行在宏任務(wù)的同步任務(wù)之后,在異步任務(wù)之前。

          代碼例子

          console.log('1'); // 宏任務(wù) 同步
          setTimeout(function() { console.log('2'); // 宏任務(wù) 異步})
          new Promise(function(resolve) { console.log('3'); // 宏任務(wù) 同步 resolve();}).then(function() { console.log('4') // 微任務(wù)})
          console.log('5') // 宏任務(wù) 同步

          以上代碼輸出順序為:1,3,5,4,2

          更多大前端技術(shù)文章:后臺回復“大前端” 獲取學習。

          參考文檔


          [1]

          你所不知道的 HSTS:?http://t.cn/AiR8pTqx

          [2]

          詳見這篇文章:?http://t.cn/AiR8pnEC

          [3]

          MIME:?http://t.cn/AiR8prtm

          [4]

          語法規(guī)范:?http://t.cn/AiR80GdO

          [5]

          這篇文章:?http://t.cn/AiR80c1k

          [6]

          what-happens-when-zh_CN:?http://t.cn/AiR80xb5

          [7]

          Tags to DOM:http://t.cn/AiR80djX

          [8]

          徹底理解瀏覽器的緩存機制:?http://t.cn/AiR8Ovob

          [9]

          瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘:?http://t.cn/AiR8Oz06

          [10]

          深入淺出瀏覽器渲染原理:?http://t.cn/AiR8O4fO

          [11]

          js引擎的執(zhí)行過程(一):http://t.cn/AiR8Ot3s




          END




          開發(fā)者技術(shù)前線?,匯集技術(shù)前線快訊和關(guān)注行業(yè)趨勢,大廠干貨,是開發(fā)者經(jīng)歷和成長的優(yōu)秀指南。
          ps:后臺回復?“電子書”?即可領(lǐng)取程序員大禮包


          好文和朋友一起看~
          瀏覽 176
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色婷婷综合在线网站 | 91POR中文字幕 | 最新爱爱视频网站 | 天天射天天干天天做 | 中文黄色三级片 |