1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 6034字,需瀏覽 13分鐘

         ·

        2022-01-14 07:55

        點(diǎn)擊上方“碼農(nóng)突圍”,馬上關(guān)注

        這里是碼農(nóng)充電第一站,回復(fù)“666”,獲取一份專屬大禮包

        真愛(ài),請(qǐng)?jiān)O(shè)置“星標(biāo)”或點(diǎn)個(gè)“在看



        # 前言


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


        這篇筆記是我這兩天看了數(shù)十篇文章總結(jié)出來(lái)的,所以相對(duì)全面一點(diǎn),但由于我是做前端的,所以會(huì)比較重點(diǎn)分析瀏覽器渲染頁(yè)面那一部分,至于其他部分我會(huì)羅列出關(guān)鍵詞,感興趣的可以自行查閱.

        注意:本文的步驟是建立在,請(qǐng)求的是一個(gè)簡(jiǎn)單的 HTTP 請(qǐng)求,沒(méi)有 HTTPS、HTTP2、最簡(jiǎn)單的 DNS、沒(méi)有代理、并且服務(wù)器沒(méi)有任何問(wèn)題的基礎(chǔ)上,盡管這是不切實(shí)際的。

        # 大致流程


        1. URL 解析

        2. DNS 查詢

        3. TCP 連接

        4. 處理請(qǐng)求

        5. 接受響應(yīng)

        6. 渲染頁(yè)面

        一、URL 解析


        地址解析:


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


        HSTS


        由于安全隱患,會(huì)使用 HSTS 強(qiáng)制客戶端使用 HTTPS 訪問(wèn)頁(yè)面。詳見(jiàn):你所不知道的 HSTS[1]。


        其他操作


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


        檢查緩存

        二、DNS 查詢


        基本步驟


        1. 瀏覽器緩存


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


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


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


        3. 路由器緩存


        路由器也有自己的緩存。


        4. ISP DNS 緩存


        ISP DNS 就是在客戶端電腦上設(shè)置的首選 DNS 服務(wù)器,它們?cè)诖蠖鄶?shù)情況下都會(huì)有緩存。


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


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

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

        需要注意的點(diǎn)


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


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


        3. 什么是 DNS 劫持


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

        三、TCP 連接


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

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


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


        • 請(qǐng)求報(bào)頭(Request Header):請(qǐng)求方法、目標(biāo)地址、遵循的協(xié)議等等

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


        其中需要注意的點(diǎn):


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

        2. 傳輸層:TCP 傳輸報(bào)文


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

        在建立連接前,會(huì)先進(jìn)行 TCP 三次握手。

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

        相關(guān)知識(shí)點(diǎn):

        1. SYN 泛洪攻擊

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


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


        判斷目標(biāo)地址是否與當(dāng)前地址處于同一網(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ù)包,每一幀分為兩個(gè)部分:


        • 標(biāo)頭:數(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 地址。每一個(gè) Mac 地址都是獨(dú)一無(wú)二的,具備了一對(duì)一的能力。


        廣播


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


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

        “相關(guān)知識(shí)點(diǎn):
        1. ARP 攻擊

        服務(wù)器接受請(qǐng)求


        接受過(guò)程就是把以上步驟逆轉(zhuǎn)過(guò)來(lái),參見(jiàn)上圖。

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


        大致流程

        HTTPD


        最常見(jiàn)的 HTTPD 有 Linux 上常用的 Apache 和 Nginx,以及 Windows 上的 IIS。


        它會(huì)監(jiān)聽(tīng)得到的請(qǐng)求,然后開(kāi)啟一個(gè)子進(jìn)程去處理這個(gè)請(qǐng)求。


        處理請(qǐng)求


        接受 TCP 報(bào)文后,會(huì)對(duì)連接進(jìn)行處理,對(duì)HTTP協(xié)議進(jìn)行解析(請(qǐng)求方法、域名、路徑等),并且進(jìn)行一些驗(yàn)證:


        • 驗(yàn)證是否配置虛擬主機(jī)

        • 驗(yàn)證虛擬主機(jī)是否接受此方法

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


        重定向


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


        URL 重寫(xiě)


        然后會(huì)查看 URL 重寫(xiě)規(guī)則,如果請(qǐng)求的文件是真實(shí)存在的,比如圖片、html、css、js文件等,則會(huì)直接把這個(gè)文件返回。


        否則服務(wù)器會(huì)按照規(guī)則把請(qǐng)求重寫(xiě)到 一個(gè) REST 風(fēng)格的 URL 上。


        然后根據(jù)動(dòng)態(tài)語(yǔ)言的腳本,來(lái)決定調(diào)用什么類型的動(dòng)態(tài)文件解釋器來(lái)處理這個(gè)請(qǐng)求。


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


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


        瀏覽器接收到來(lái)自服務(wù)器的響應(yīng)資源后,會(huì)對(duì)資源進(jìn)行分析。


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


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


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


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


        六、渲染頁(yè)面


        瀏覽器內(nèi)核

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


        基本流程


        6.1. HTML 解析


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


        解析的過(guò)程可以分為四個(gè)步驟:


        ① 解碼(encoding)


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


        ② 預(yù)解析(pre-parsing)


        預(yù)解析做的事情是提前加載資源,減少處理時(shí)間,它會(huì)識(shí)別一些會(huì)請(qǐng)求資源的屬性,比如img標(biāo)簽的src屬性,并將這個(gè)請(qǐng)求加到請(qǐng)求隊(duì)列中。


        ③ 符號(hào)化(Tokenization)


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


        它通過(guò)一個(gè)狀態(tài)機(jī)去識(shí)別符號(hào)的狀態(tài),比如遇到<,>狀態(tài)都會(huì)產(chǎn)生變化。


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

        “注意:符號(hào)化和構(gòu)建樹(shù)是并行操作的,也就是說(shuō)只要解析到一個(gè)開(kāi)始標(biāo)簽,就會(huì)創(chuàng)建一個(gè) DOM 節(jié)點(diǎn)?!?/span>

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


        Web page parsing

        Web page parsing

        This is an example Web page.

        瀏覽器容錯(cuò)進(jìn)制

        你從來(lái)沒(méi)有在瀏覽器看過(guò)類似”語(yǔ)法無(wú)效”的錯(cuò)誤,這是因?yàn)闉g覽器去糾正錯(cuò)誤的語(yǔ)法,然后繼續(xù)工作。


        事件


        當(dāng)整個(gè)解析的過(guò)程完成以后,瀏覽器會(huì)通過(guò)DOMContentLoaded事件來(lái)通知DOM解析完成。


        6.2. CSS 解析


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


        CSS 匹配規(guī)則


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


        所以我們寫(xiě) CSS 時(shí),盡量用 id 和 class,千萬(wàn)不要過(guò)度層疊。

        6.3. 渲染樹(shù)


        其實(shí)這就是一個(gè) DOM 樹(shù)和 CSS 規(guī)則樹(shù)合并的過(guò)程。

        “注意:渲染樹(shù)會(huì)忽略那些不需要渲染的節(jié)點(diǎn),比如設(shè)置了display:none的節(jié)點(diǎn)?!?/span>


        計(jì)算


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


        級(jí)聯(lián)


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


        1. 標(biāo)簽名、class、id

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

        3. !important


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


        渲染阻塞


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


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


        所有我們知道:


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

        • JS 會(huì)阻塞后面的 DOM 解析


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


        • CSS 資源排在 JavaScript 資源前面

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


        另外,如果要改變阻塞模式,可以使用 defer 與 async


        6.4. 布局與繪制


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


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

        6.5. 合并渲染層


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


        6.6. 回流與重繪


        回流(reflow)


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


        reflow基本是無(wú)法避免的,因?yàn)楫?dāng)你滑動(dòng)一下鼠標(biāo)、resize 窗口,頁(yè)面就會(huì)產(chǎn)生變化。


        重繪(repaint)


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


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


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


        比如:

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


        6.7. JavaScript 編譯執(zhí)行


        大致流程

        可以分為三個(gè)階段:


        1. 詞法分析


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


        幾個(gè)步驟:


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

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

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


        2. 預(yù)編譯


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


        • 全局環(huán)境

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

        • eval


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


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


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


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

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

        • 建立作用域鏈

          • 確認(rèn)當(dāng)前執(zhí)行環(huán)境是否能訪問(wèn)變量

        • 確定 This 指向

        3. 執(zhí)行


        JS 線程

        雖然 JS 是單線程的,但實(shí)際上參與工作的線程一共有四個(gè):

        “其中三個(gè)只是協(xié)助,只有 JS 引擎線程是真正執(zhí)行的”
        • JS 引擎線程:也叫 JS 內(nèi)核,負(fù)責(zé)解析執(zhí)行 JS 腳本程序的主線程,例如 V8 引擎

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

        • 定時(shí)器觸發(fā)線程:主要控制setInterval和setTimeout,用來(lái)計(jì)時(shí),計(jì)時(shí)完畢后,則把定時(shí)器的處理函數(shù)推進(jìn)事件隊(duì)列中,等待 JS 引擎線程。

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


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


        宏任務(wù)


        分為:

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

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


        微任務(wù)


        微任務(wù)是ES6和Node環(huán)境下的,主要 API 有:Promise,process.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ù) 同步

        以上代碼輸出順序?yàn)椋?,3,5,4,2

        # 參考文檔


        [1]你所不知道的 HSTS:?http://t.cn/AiR8pTqx
        [2]詳見(jiàn)這篇文章:?http://t.cn/AiR8pnEC
        [3]MIME:?http://t.cn/AiR8prtm
        [4]語(yǔ)法規(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]徹底理解瀏覽器的緩存機(jī)制:?http://t.cn/AiR8Ovob
        [9]瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘: http://t.cn/AiR8Oz06
        [10]深入淺出瀏覽器渲染原理:?http://t.cn/AiR8O4fO
        [11]js引擎的執(zhí)行過(guò)程(一):http://t.cn/AiR8Ot3s

        來(lái)源:https://4ark.me/post/b6c7c0a2.html

        -End-

        最近有一些小伙伴,讓我?guī)兔φ乙恍?面試題?資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來(lái),可以說(shuō)是程序員面試必備!所有資料都整理到網(wǎng)盤(pán)了,歡迎下載!

        點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

        瀏覽 102
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            大鸡巴操B视频 | 夜夜撸夜夜操 | 无码秘 人妻一区红中av | 操逼视频在线观看网站 | 可以看黄的视频 | 特黄特爽特刺激的视频 | 欧美日韩在线观看视频 | 国产成人在线观看黄片 | 最近最新中文字幕豆花 | 日韩丝袜少妇 |