<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>

          在瀏覽器輸入 URL 回車之后發(fā)生了什么(流程圖,超詳細(xì)版)

          共 6022字,需瀏覽 13分鐘

           ·

          2021-05-29 12:21

          點(diǎn)擊上方“碼農(nóng)突圍”,馬上關(guān)注
          這里是碼農(nóng)充電第一站,回復(fù)“666”,獲取一份專屬大禮包
          真愛,請?jiān)O(shè)置“星標(biāo)”或點(diǎn)個“在看
          作者:4Ark
          來源:https://4ark.me/post/b6c7c0a2.html

          前言

          這個問題已經(jīng)是老生常談了,更是經(jīng)常被作為面試的壓軸題出現(xiàn),網(wǎng)上也有很多文章,但最近閑的無聊,然后就自己做了一篇筆記,感覺比之前理解更透徹了。
          這篇筆記是我這兩天看了數(shù)十篇文章總結(jié)出來的,所以相對全面一點(diǎn),但由于我是做前端的,所以會比較重點(diǎn)分析瀏覽器渲染頁面那一部分,至于其他部分我會羅列出關(guān)鍵詞,感興趣的可以自行查閱,
          注意:本文的步驟是建立在,請求的是一個簡單的 HTTP 請求,沒有 HTTPS、HTTP2、最簡單的 DNS、沒有代理、并且服務(wù)器沒有任何問題的基礎(chǔ)上,盡管這是不切實(shí)際的。

          大致流程

          1、URL 解析
          2、DNS 查詢
          3、TCP 連接
          4、處理請求
          5、接受響應(yīng)
          6、渲染頁面

          一、URL 解析

          地址解析

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

          HSTS

          由于安全隱患,會使用 HSTS 強(qiáng)制客戶端使用 HTTPS 訪問頁面。詳見:你所不知道的 HSTS。

          其他操作

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

          檢查緩存

          二、DNS 查詢

          基本步驟

          1、瀏覽器緩存

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

          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)上的根域,下面這個圖很好的詮釋了整個流程:

          需要注意的點(diǎn)

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

          三、TCP 連接

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

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

          在前面的步驟我們已經(jīng)得到服務(wù)器的 IP 地址,瀏覽器會開始構(gòu)造一個 HTTP 報文,其中包括:
          請求報頭(Request Header):
          請求方法、目標(biāo)地址、遵循的協(xié)議等等
          請求主體(其他參數(shù))
          其中需要注意的點(diǎn):
          瀏覽器只能發(fā)送 GET、POST 方法,而打開網(wǎng)頁使用的是 GET 方法

          2、傳輸層:TCP 傳輸報文

          傳輸層會發(fā)起一條到達(dá)服務(wù)器的 TCP 連接,為了方便傳輸,會對數(shù)據(jù)進(jìn)行分割(以報文段為單位),并標(biāo)記編號,方便服務(wù)器接受時能夠準(zhǔn)確地還原報文信息。整編:微信公眾號,搜云庫技術(shù)團(tuán)隊(duì),ID:souyunku
          在建立連接前,會先進(jìn)行 TCP 三次握手。
          關(guān)于 TCP/IP 三次握手,網(wǎng)上已經(jīng)有很多段子和圖片生動地描述了。
          相關(guān)知識點(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ù)包,每一幀分為兩個部分:
          標(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 地址。每一個 Mac 地址都是獨(dú)一無二的,具備了一對一的能力。
          廣播
          發(fā)送數(shù)據(jù)的方法很原始,直接把數(shù)據(jù)通過 ARP 協(xié)議,向本網(wǎng)絡(luò)的所有機(jī)器發(fā)送,接收方根據(jù)標(biāo)頭信息與自身 Mac 地址比較,一致就接受,否則丟棄。
          注意:接收方回應(yīng)是單播。
          相關(guān)知識點(diǎn):
          1、ARP 攻擊
          服務(wù)器接受請求
          接受過程就是把以上步驟逆轉(zhuǎn)過來,參見上圖。

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

          大致流程

          HTTPD

          最常見的 HTTPD 有 Linux 上常用的 Apache 和 Nginx,以及 Windows 上的 IIS。
          它會監(jiān)聽得到的請求,然后開啟一個子進(jìn)程去處理這個請求。整編:微信公眾號,搜云庫技術(shù)團(tuán)隊(duì),ID:souyunku

          處理請求

          接受 TCP 報文后,會對連接進(jìn)行處理,對HTTP協(xié)議進(jìn)行解析(請求方法、域名、路徑等),并且進(jìn)行一些驗(yàn)證:
          1、驗(yàn)證是否配置虛擬主機(jī)
          2、驗(yàn)證虛擬主機(jī)是否接受此方法
          3、驗(yàn)證該用戶可以使用該方法(根據(jù) IP 地址、身份信息等)

          重定向

          假如服務(wù)器配置了 HTTP 重定向,就會返回一個 301永久重定向響應(yīng),瀏覽器就會根據(jù)響應(yīng),重新發(fā)送 HTTP 請求(重新執(zhí)行上面的過程)。
          關(guān)于更多:詳見這篇文章

          URL 重寫

          然后會查看 URL 重寫規(guī)則,如果請求的文件是真實(shí)存在的,比如圖片、html、css、js文件等,則會直接把這個文件返回。
          否則服務(wù)器會按照規(guī)則把請求重寫到 一個 REST 風(fēng)格的 URL 上。
          然后根據(jù)動態(tài)語言的腳本,來決定調(diào)用什么類型的動態(tài)文件解釋器來處理這個請求。
          以 PHP 語言的 MVC 框架舉例,它首先會初始化一些環(huán)境的參數(shù),根據(jù) URL 由上到下地去匹配路由,然后讓路由所定義的方法去處理請求。

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

          瀏覽器接收到來自服務(wù)器的響應(yīng)資源后,會對資源進(jìn)行分析。
          首先查看 Response header,根據(jù)不同狀態(tài)碼做不同的事(比如上面提到的重定向)。
          如果響應(yīng)資源進(jìn)行了壓縮(比如 gzip),還需要進(jìn)行解壓。整編:微信公眾號,搜云庫技術(shù)團(tuán)隊(duì),ID:souyunku
          然后,對響應(yīng)資源做緩存。
          接下來,根據(jù)響應(yīng)資源里的 MIME 類型去解析響應(yīng)內(nèi)容(比如 HTML、Image各有不同的解析方式)。

          六、渲染頁面

          瀏覽器內(nèi)核

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

          基本流程

          1、HTML 解析

          首先要知道瀏覽器解析是從上往下一行一行地解析的。
          解析的過程可以分為四個步驟:
          1. 解碼(encoding)
          傳輸回來的其實(shí)都是一些二進(jìn)制字節(jié)數(shù)據(jù),瀏覽器需要根據(jù)文件指定編碼(例如UTF-8)轉(zhuǎn)換成字符串,也就是HTML 代碼。
          2. 預(yù)解析(pre-parsing)
          預(yù)解析做的事情是提前加載資源,減少處理時間,它會識別一些會請求資源的屬性,比如 img標(biāo)簽的 src屬性,并將這個請求加到請求隊(duì)列中。
          3. 符號化(Tokenization)
          符號化是詞法分析的過程,將輸入解析成符號,HTML 符號包括,開始標(biāo)簽、結(jié)束標(biāo)簽、屬性名和屬性值。
          它通過一個狀態(tài)機(jī)去識別符號的狀態(tài),比如遇到 <, >狀態(tài)都會產(chǎn)生變化。
          4. 構(gòu)建樹(tree construction)
          注意:符號化和構(gòu)建樹是并行操作的,也就是說只要解析到一個開始標(biāo)簽,就會創(chuàng)建一個 DOM 節(jié)點(diǎn)。
          在上一步符號化中,解析器獲得這些標(biāo)記,然后以合適的方法創(chuàng)建 DOM對象并把這些符號插入到 DOM對象中。
          1. <html>

          2. <head>

          3. <title>Web page parsing</title>

          4. </head>

          5. <body>

          6. <div>

          7. <h1>Web page parsing</h1>

          8. <p>This is an example Web page.</p>

          9. </div>

          10. </body>

          11. </html>

          瀏覽器容錯進(jìn)制
          你從來沒有在瀏覽器看過類似”語法無效”的錯誤,這是因?yàn)闉g覽器去糾正錯誤的語法,然后繼續(xù)工作。
          事件
          當(dāng)整個解析的過程完成以后,瀏覽器會通過 DOMContentLoaded事件來通知 DOM解析完成。

          2、CSS 解析

          一旦瀏覽器下載了 CSS,CSS 解析器就會處理它遇到的任何 CSS,根據(jù)語法規(guī)范解析出所有的 CSS 并進(jìn)行標(biāo)記化,然后我們得到一個規(guī)則表。
          CSS 匹配規(guī)則
          在匹配一個節(jié)點(diǎn)對應(yīng)的 CSS 規(guī)則時,是按照從右到左的順序的,例如:div p{font-size:14px}會先尋找所有的 p標(biāo)簽然后判斷它的父元素是否為 div
          所以我們寫 CSS 時,盡量用 id 和 class,千萬不要過度層疊。

          3、 渲染樹

          其實(shí)這就是一個 DOM 樹和 CSS 規(guī)則樹合并的過程。
          注意:渲染樹會忽略那些不需要渲染的節(jié)點(diǎn),比如設(shè)置了 display:none的節(jié)點(diǎn)。
          計(jì)算
          通過計(jì)算讓任何尺寸值都減少到三個可能之一:auto、百分比、px,比如把 rem轉(zhuǎn)化為 px。
          級聯(lián)
          瀏覽器需要一種方法來確定哪些樣式才真正需要應(yīng)用到對應(yīng)元素,所以它使用一個叫做 specificity的公式,這個公式會通過:
          1、標(biāo)簽名、class、id
          2、是否內(nèi)聯(lián)樣式
          3、 !important
          然后得出一個權(quán)重值,取最高的那個。
          渲染阻塞
          當(dāng)遇到一個 script標(biāo)簽時,DOM 構(gòu)建會被暫停,直至腳本完成執(zhí)行,然后繼續(xù)構(gòu)建 DOM 樹。
          但如果 JS 依賴 CSS 樣式,而它還沒有被下載和構(gòu)建時,瀏覽器就會延遲腳本執(zhí)行,直至 CSS Rules 被構(gòu)建。
          所有我們知道:
          1、CSS 會阻塞 JS 執(zhí)行
          2、JS 會阻塞后面的 DOM 解析
          為了避免這種情況,應(yīng)該以下原則:
          1、CSS 資源排在 JavaScript 資源前面
          2、JS 放在 HTML 最底部,也就是 </body>
          另外,如果要改變阻塞模式,可以使用 defer 與 async,詳見:這篇文章

          4、布局與繪制

          確定渲染樹種所有節(jié)點(diǎn)的幾何屬性,比如:位置、大小等等,最后輸入一個盒子模型,它能精準(zhǔn)地捕獲到每個元素在屏幕內(nèi)的準(zhǔn)確位置與大小。
          然后遍歷渲染樹,調(diào)用渲染器的 paint() 方法在屏幕上顯示其內(nèi)容。

          5、合并渲染層

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

          6、 回流與重繪

          回流(reflow)
          當(dāng)瀏覽器發(fā)現(xiàn)某個部分發(fā)現(xiàn)變化影響了布局時,需要倒回去重新渲染,會從 html標(biāo)簽開始遞歸往下,重新計(jì)算位置和大小。整編:微信公眾號,搜云庫技術(shù)團(tuán)隊(duì),ID:souyunku
          reflow基本是無法避免的,因?yàn)楫?dāng)你滑動一下鼠標(biāo)、resize 窗口,頁面就會產(chǎn)生變化。
          重繪(repaint)
          改變了某個元素的背景色、文字顏色等等不會影響周圍元素的位置變化時,就會發(fā)生重繪。
          每次重繪后,瀏覽器還需要合并渲染層并輸出到屏幕上。
          回流的成本要比重繪高很多,所以我們應(yīng)該盡量避免產(chǎn)生回流。
          比如:
          display:none 會觸發(fā)回流,而 visibility:hidden 只會觸發(fā)重繪。

          7、JavaScript 編譯執(zhí)行

          大致流程
          可以分為三個階段:

          1、詞法分析

          JS 腳本加載完畢后,會首先進(jìn)入語法分析階段,它首先會分析代碼塊的語法是否正確,不正確則拋出“語法錯誤”,停止執(zhí)行。
          幾個步驟:
          分詞,例如將 vara=2,,分成 var、 a=、 2這樣的詞法單元。
          解析,將詞法單元轉(zhuǎn)換成抽象語法樹(AST)。
          代碼生成,將抽象語法樹轉(zhuǎn)換成機(jī)器指令。

          2、預(yù)編譯

          JS 有三種運(yùn)行環(huán)境:
          1、全局環(huán)境
          2、函數(shù)環(huán)境
          3、eval
          每進(jìn)入一個不同的運(yùn)行環(huán)境都會創(chuàng)建一個對應(yīng)的執(zhí)行上下文,根據(jù)不同的上下文環(huán)境,形成一個函數(shù)調(diào)用棧,棧底永遠(yuǎn)是全局執(zhí)行上下文,棧頂則永遠(yuǎn)是當(dāng)前執(zhí)行上下文。
          創(chuàng)建執(zhí)行上下文
          創(chuàng)建執(zhí)行上下文的過程中,主要做了以下三件事:
          • 創(chuàng)建變量對象

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

          • 建立作用域鏈

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

          • 確定 This 指向

          3、執(zhí)行

          JS 線程
          雖然 JS 是單線程的,但實(shí)際上參與工作的線程一共有四個:
          其中三個只是協(xié)助,只有 JS 引擎線程是真正執(zhí)行的
          JS 引擎線程:
          也叫 JS 內(nèi)核,負(fù)責(zé)解析執(zhí)行 JS 腳本程序的主線程,例如 V8 引擎
          事件觸發(fā)線程:
          屬于瀏覽器內(nèi)核線程,主要用于控制事件,例如鼠標(biāo)、鍵盤等,當(dāng)事件被觸發(fā)時,就會把事件的處理函數(shù)推進(jìn)事件隊(duì)列,等待 JS 引擎線程執(zhí)行。整編:微信公眾號,搜云庫技術(shù)團(tuán)隊(duì),ID:souyunku
          定時器觸發(fā)線程:
          主要控制 setIntervalsetTimeout,用來計(jì)時,計(jì)時完畢后,則把定時器的處理函數(shù)推進(jìn)事件隊(duì)列中,等待 JS 引擎線程。
          HTTP 異步請求線程:
          通過XMLHttpRequest連接后,通過瀏覽器新開的一個線程,監(jiān)控readyState狀態(tài)變更時,如果設(shè)置了該狀態(tài)的回調(diào)函數(shù),則將該狀態(tài)的處理函數(shù)推進(jìn)事件隊(duì)列中,等待JS引擎線程執(zhí)行。
          注:瀏覽器對同一域名的并發(fā)連接數(shù)是有限的,通常為 6 個。
          宏任務(wù)
          分為:
          1、同步任務(wù):按照順序執(zhí)行,只有前一個任務(wù)完成后,才能執(zhí)行后一個任務(wù)
          2、異步任務(wù):不直接執(zhí)行,只有滿足觸發(fā)條件時,相關(guān)的線程將該異步任務(wù)推進(jìn)任務(wù)隊(duì)列中,等待JS引擎主線程上的任務(wù)執(zhí)行完畢時才開始執(zhí)行,例如異步Ajax、DOM事件,setTimeout等。
          微任務(wù)
          微任務(wù)是ES6和Node環(huán)境下的,主要 API 有:Promise, process.nextTick
          微任務(wù)的執(zhí)行在宏任務(wù)的同步任務(wù)之后,在異步任務(wù)之前。
          代碼例子
          1. console.log('1'); // 宏任務(wù) 同步


          2. setTimeout(function() {

          3. console.log('2'); // 宏任務(wù) 異步

          4. })


          5. newPromise(function(resolve) {

          6. console.log('3'); // 宏任務(wù) 同步

          7. resolve();

          8. }).then(function() {

          9. console.log('4') // 微任務(wù)

          10. })


          11. console.log('5') // 宏任務(wù) 同步

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

          最近熱文

          ?  拆解 1968年 的美國軍用計(jì)算機(jī),真的懷疑是 “ 穿越 ” ?。?/a>
          ?  再見!收費(fèi)的XShell,我改用國產(chǎn)良心工具!
          ?  ERP已死,“中臺”已涼,“低代碼”稱王!
          ?  “我辭退了一位學(xué)位學(xué)歷造假的程序員”

          瀏覽 62
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  99热这里有精品 | 久久精品久久久久 | 蜜桃成人无码 | 国产二区在线视频观看 | 天天色五月 |