對(duì)于面試常問的從瀏覽器輸入 URL
到頁面展示過程發(fā)生了什么?,我想大家都或多或少能說出一二。但是,其實(shí)這個(gè)問題很有深度,而你是否回答的有深度,在很大程度上會(huì)影響到面試官對(duì)你的印象。
并且,網(wǎng)上各種資料都是淺嘗輒止地講解這個(gè)過程,經(jīng)常會(huì)出現(xiàn)今天看到這個(gè)版本,明天看到另一個(gè)版本地情況。所以,這次我們就來深入淺出一下這整個(gè)過程~
首先,在開始講解整個(gè)過程前,我們需要認(rèn)識(shí)一下 Chrome
多進(jìn)程架構(gòu)。因?yàn)?,從瀏覽器輸入 URL
到頁面渲染的整個(gè)過程都是由 Chrome
架構(gòu)中的各個(gè)進(jìn)程之間的配合完成。
Chrome
的多進(jìn)程架構(gòu):
HTML
文檔和 JavaScript
等轉(zhuǎn)化為用戶界面HTTP
請(qǐng)求、WebSocket
模塊GPU
(圖形處理器)進(jìn)程,它負(fù)責(zé)對(duì) UI
界面的展示發(fā)生這個(gè)過程的前提,用戶在地址欄中輸入了 URL
,而地址欄會(huì)根據(jù)用戶輸入,做出如下判斷:
URL
結(jié)構(gòu)的字符串,則會(huì)用瀏覽器默認(rèn)的搜索引擎搜索該字符串URL
結(jié)構(gòu)字符串,則會(huì)構(gòu)建完整的 URL
結(jié)構(gòu),瀏覽器進(jìn)程會(huì)將完整的 URL
通過進(jìn)程間通信,即 IPC
,發(fā)送給網(wǎng)絡(luò)進(jìn)程在網(wǎng)絡(luò)進(jìn)程接收到 URL
后,并不是馬上對(duì)指定 URL
進(jìn)行請(qǐng)求。首先,我們需要進(jìn)行 DNS
解析域名得到對(duì)應(yīng)的 IP
,然后通過 ARP
解析 IP
得到對(duì)應(yīng)的 MAC
(Media Access Control Address
)地址。
域名是我們?nèi)〈洃洀?fù)雜的IP
的一種解決方案,而IP
地址才是目標(biāo)在網(wǎng)絡(luò)中所被分配的節(jié)點(diǎn)。MAC
地址是對(duì)應(yīng)目標(biāo)網(wǎng)卡所在的固定地址。
1. DNS 解析
而 DNS
解析域名的過程分為以下幾個(gè)步驟:
DNS
緩存DNS
緩存(即查找本地 host
文件)ISP
(Internet Service Provider
)互聯(lián)網(wǎng)服務(wù)提供商(例如電信、移動(dòng))的 DNS
服務(wù)器2. 通信過程
首先,建立 TCP
連接,即三次握手過程:
SYN
的數(shù)據(jù)包,表示我將要發(fā)送請(qǐng)求。SYN/ACK
的數(shù)據(jù)包,表示我已經(jīng)收到通知,告知客戶端發(fā)送請(qǐng)求。ACK
的數(shù)據(jù)包,表示我要開始發(fā)送請(qǐng)求,準(zhǔn)備被接受。然后,利用 TCP
通道進(jìn)行數(shù)據(jù)傳輸:
TCP
的重發(fā)機(jī)制TCP
頭中的需要進(jìn)行排序,形成完整的數(shù)據(jù)最后,斷開 TCP
連接,即四次握手過程:
而這整個(gè)過程的客戶端則是網(wǎng)絡(luò)進(jìn)程。并且,在數(shù)據(jù)傳輸?shù)倪^程還可能會(huì)發(fā)生的重定向的情況,即當(dāng)網(wǎng)絡(luò)進(jìn)程接收到狀態(tài)碼為 3xx 的響應(yīng)報(bào)文,則會(huì)根據(jù)響應(yīng)報(bào)文首部字段中的 Location 字段的值進(jìn)行重新向,即會(huì)重新發(fā)起請(qǐng)求
3. 數(shù)據(jù)處理
當(dāng)網(wǎng)絡(luò)進(jìn)程接收到的響應(yīng)報(bào)文狀態(tài)碼,進(jìn)行相應(yīng)的操作。例如狀態(tài)碼為 200 OK
時(shí),會(huì)解析響應(yīng)報(bào)文中的 Content-Type
首部字段,例如我們這個(gè)過程 Content-Type
會(huì)出現(xiàn) application/javascript
、text/css
、text/html
,即對(duì)應(yīng) Javascript
文件、CSS
文件、HTML
文件。
詳細(xì)的 MIME
類型講解可以看 MDN
當(dāng)前需要渲染 HTML
時(shí),則需要?jiǎng)?chuàng)建渲染進(jìn)程,用于后期渲染 HTML
。而對(duì)于渲染進(jìn)程,如果是同一站點(diǎn)是可以共享一個(gè)渲染進(jìn)程,例如 a.abc.com
和 c.abc.com
可以共享一個(gè)渲染渲染進(jìn)程。否則,需要重新創(chuàng)建渲染進(jìn)程
需要注意的是,同站指的是頂級(jí)域名和二級(jí)域名相等
在創(chuàng)建完渲染進(jìn)程后,網(wǎng)絡(luò)進(jìn)程會(huì)將接收到的 HTML、JavaScript 等數(shù)據(jù)傳遞給渲染進(jìn)程。而在渲染進(jìn)程接收完數(shù)據(jù)后,此時(shí)用戶界面上會(huì)發(fā)生這幾件事:
URL
enable
,顯示正在加載狀態(tài)大家都知道頁面渲染的過程也是面試中單獨(dú)會(huì)考的點(diǎn),并且時(shí)常會(huì)由這個(gè)點(diǎn)延申出另一個(gè)問題,即如何避免回流和重繪。
渲染過程,是整個(gè)從理器輸入 URL 到頁面渲染過程的最后一步。而頁面渲染的過程可以分為 9 個(gè)步驟:
HTML
生成 DOM
樹CSS
生成 CSSOM
JavaScript
Render Tree
)由于網(wǎng)絡(luò)進(jìn)程傳輸給渲染進(jìn)程的是 HTML
字符串,所以,渲染進(jìn)程需要將 HTML
字符串轉(zhuǎn)化成 DOM
樹。例如:
需要注意的是這個(gè)DOM
樹不同于Chrome-devtool
中Element
選項(xiàng)卡的DOM
樹,它是存在內(nèi)存中的,用于提供JavaScript
對(duì)DOM
的操作。
構(gòu)建 CSSOM
的過程,即通過解析 CSS
文件、style
標(biāo)簽、行內(nèi) style
等,生成 CSSOM
。而這個(gè)過程會(huì)做這幾件事:
CSS
,即將 color: blue
轉(zhuǎn)化成 color: rgb()
形式,可以理解成類似 ES6
轉(zhuǎn) ES5
的過程CSS
樣式會(huì)繼承父級(jí)的樣式,如 font-size
、color
之類的。CSS Object Model
是一組允許用JavaScript
操縱CSS
的API
。詳細(xì)API
講解可以看 MDN
通常情況下,在構(gòu)建 DOM
樹或 CSSOM
的同時(shí),如果也要加載 JavaScript
,則會(huì)造成前者的構(gòu)建的暫停。當(dāng)然,我們可以通過 defer
或 sync
來實(shí)現(xiàn)異步加載 JavaScript
。雖然 defer
和 sync
都可以實(shí)現(xiàn)異步加載 JavaScript
,但是前者是在加載后,等待 CSSOM
和 DOM
樹構(gòu)建完后才執(zhí)行 JavaScript
,而后者是在異步加載完馬上執(zhí)行,即使用 sync
的方式仍然會(huì)造成阻塞。
而 JavaScript
執(zhí)行的過程,即編譯和運(yùn)行 JavaScript
的過程。由于 JavaScript
是解釋型的語言。所以這個(gè)過程會(huì)是這樣的:
Token
化Token
,生成 AST
(Abstract Sytanx Tree
) 抽象語法樹和創(chuàng)建上下文AST
,生成字節(jié)碼。在有了 DOM
樹和 CSSOM
之后,需要將兩者結(jié)合生成渲染樹 Render Tree
,并且這個(gè)過程會(huì)去除掉那些 display: node
的節(jié)點(diǎn)。此時(shí),渲染樹就具備元素和元素的樣式信息。
根據(jù) Render Tree
渲染樹,對(duì)樹中每個(gè)節(jié)點(diǎn)進(jìn)行計(jì)算,確定每個(gè)節(jié)點(diǎn)在頁面中的寬度、高度和位置。
需要注意的是,第一次確定節(jié)點(diǎn)的大小和位置的過程稱為布局,而第二次才被稱為回流
由于層疊上下文的存在,渲染引擎會(huì)為具備層疊上下文的元素創(chuàng)建對(duì)應(yīng)的圖層,而諸多圖層的疊加就形成了我們看到的一些頁面效果。例如,一些 3D
的效果、動(dòng)畫就是基于圖層而形成的。
值得一提的是,對(duì)于內(nèi)容溢出存在滾輪的情況也會(huì)進(jìn)行分層
對(duì)于存在圖層的頁面部分,需要進(jìn)行有序的繪制,而對(duì)于這個(gè)過程,渲染引擎會(huì)將一個(gè)個(gè)圖層的繪制拆分成繪制指令,并按照?qǐng)D層繪制順序形成一個(gè)繪制列表。
有了繪制列表后,渲染引擎中的合成線程會(huì)根據(jù)當(dāng)前視口的大小將圖層進(jìn)行分塊處理,然后合成線程會(huì)對(duì)視口附近的圖塊生成位圖,即光柵化。而渲染進(jìn)程也維護(hù)了一個(gè)柵格化的線程池,專門用于將圖塊轉(zhuǎn)為位圖。
柵格化的過程通常會(huì)使用GPU
加速,例如使用wil-change
、opacity
,就會(huì)通過GPU
加速顯示
當(dāng)所有的圖塊都經(jīng)過柵格化處理后,渲染引擎中的合成線程會(huì)生成繪制圖塊的指令,提交給瀏覽器進(jìn)程。然后瀏覽器進(jìn)程將頁面繪制到內(nèi)存中。最后將內(nèi)存繪制結(jié)果顯示在用戶界面上。
而這個(gè)整個(gè)從生成繪制列表、光柵化、顯示的過程,就是我們常說的重繪的過程
整個(gè)瀏覽器輸入 URL 到頁面渲染的過程涉及到的知識(shí)點(diǎn)非常廣,如 Chrome
多進(jìn)程的架構(gòu)、HTTP
通信過程、瀏覽器解析 JavaScript
過程、瀏覽器繪制頁面過程以及一些計(jì)算機(jī)的基礎(chǔ)知識(shí)等等,并且,這整個(gè)過程的分析其實(shí)和 Chrome-devtools
密切相關(guān),所以很好的使用 Chrome-devtools
是非常重要的,后續(xù)應(yīng)該會(huì)出一篇關(guān)于使用 Chrome-devtools
的指南。當(dāng)然,本篇文章仍然存在諸多不足,歡迎提 issue
~
寫作不易,如果你覺得有收獲的話,可以帥氣三連擊?。?!
聯(lián)系客服