著名前端面試題:
一個(gè)頁(yè)面從輸入 URL 到頁(yè)面加載顯示完成,這個(gè)過(guò)程中都發(fā)生了什么?
主要包括以下幾個(gè)基本步驟:
- 瀏覽器的地址欄輸入U(xiǎn)RL并按下回車(chē)。
- 瀏覽器查找當(dāng)前URL是否存在緩存,并比較緩存是否過(guò)期。
- DNS解析URL對(duì)應(yīng)的IP。
- 根據(jù)IP建立TCP連接(三次握手)。
- HTTP發(fā)起請(qǐng)求。
- 服務(wù)器處理請(qǐng)求,瀏覽器接收HTTP響應(yīng)。
- 渲染頁(yè)面,構(gòu)建DOM樹(shù)。
- 關(guān)閉TCP連接(四次揮手)。
接下來(lái)對(duì)其中幾個(gè)步驟展開(kāi)說(shuō)一下
1. URL
輸入U(xiǎn)RL后,會(huì)進(jìn)行解析(URL的本質(zhì)就是統(tǒng)一資源定位符)
URL一般包括幾大部分:
- protocol,協(xié)議頭,譬如有http,加密的https,ftp等
- host,主機(jī)域名或IP地址
- port,端口號(hào)(通常端口號(hào)不常見(jiàn)是因?yàn)榇蟛糠值亩际鞘褂媚J(rèn)的端口所以隱藏,如HTTP默認(rèn)端口80,HTTPS默認(rèn)端口443。)
- path,目錄路徑
- query,即查詢(xún)參數(shù)
- fragment,即#后的hash值,一般用來(lái)定位到某個(gè)位置
其他面試官可能問(wèn)的知識(shí)點(diǎn):同源策略,跨域的問(wèn)題(待補(bǔ)充)
2.緩存
根據(jù)下圖的邏輯,判斷是直接使用緩存內(nèi)容還是重新向服務(wù)器請(qǐng)求資源

3.DNS域名解析
我們知道在地址欄輸入的域名并不是最后資源所在的真實(shí)位置,域名只是與IP地址的一個(gè)映射。網(wǎng)絡(luò)服務(wù)器的IP地址那么多,我們不可能去記一串串的數(shù)字,因此域名就產(chǎn)生了,域名解析的過(guò)程實(shí)際是將域名還原為IP地址的過(guò)程。
首先瀏覽器先檢查本地hosts文件是否有這個(gè)網(wǎng)址映射關(guān)系,如果有就調(diào)用這個(gè)IP地址映射,完成域名解析。
如果沒(méi)找到則會(huì)查找本地DNS解析器緩存,如果查找到則返回。
如果還是沒(méi)有找到則會(huì)查找本地DNS服務(wù)器,如果查找到則返回。
最后迭代查詢(xún),按根域服務(wù)器 ->頂級(jí)域,.com->第二層域,baidu.com ->子域,www.baidu.com的順序找到IP地址。
4.TCP連接
在通過(guò)第一步的DNS域名解析后,獲取到了服務(wù)器的IP地址,在獲取到IP地址后,便會(huì)開(kāi)始建立一次連接,這是由TCP協(xié)議完成的,主要通過(guò)三次握手進(jìn)行連接。
- 第一次握手: 建立連接時(shí),客戶(hù)端發(fā)送syn包(seq=x)到服務(wù)器,并進(jìn)入SYN_SENT狀態(tài),等待服務(wù)器確認(rèn);
- 第二次握手: 服務(wù)器收到syn包,必須確認(rèn)客戶(hù)的SYN(ack=x+1),同時(shí)自己也發(fā)送一個(gè)SYN包(seq=y),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
- 第三次握手: 客戶(hù)端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=y+1),此包發(fā)送完畢,客戶(hù)端和服務(wù)器進(jìn)入ESTABLISHED(TCP連接成功)狀態(tài),完成三次握手。
完成三次握手,客戶(hù)端與服務(wù)器開(kāi)始傳送數(shù)據(jù)。

5. 瀏覽器向服務(wù)器發(fā)送HTTP請(qǐng)求
完整的HTTP請(qǐng)求包含請(qǐng)求起始行、請(qǐng)求頭部、請(qǐng)求主體三部分。

常用的請(qǐng)求頭部(部分)
Accept: 接收類(lèi)型,表示瀏覽器支持的MIME類(lèi)型
(對(duì)標(biāo)服務(wù)端返回的Content-Type)
Accept-Encoding:瀏覽器支持的壓縮類(lèi)型,如gzip等,超出類(lèi)型不能接收
Content-Type:客戶(hù)端發(fā)送出去實(shí)體內(nèi)容的類(lèi)型
Cache-Control: 指定請(qǐng)求和響應(yīng)遵循的緩存機(jī)制,如no-cache
If-Modified-Since:對(duì)應(yīng)服務(wù)端的Last-Modified,用來(lái)匹配看文件是否變動(dòng),只能精確到1s之內(nèi),http1.0中
Expires:緩存控制,在這個(gè)時(shí)間內(nèi)不會(huì)請(qǐng)求,直接使用緩存,http1.0,而且是服務(wù)端時(shí)間
Max-age:代表資源在本地緩存多少秒,有效時(shí)間內(nèi)不會(huì)請(qǐng)求,而是使用緩存,http1.1中
If-None-Match:對(duì)應(yīng)服務(wù)端的ETag,用來(lái)匹配文件內(nèi)容是否改變(非常精確),http1.1中
Cookie: 有cookie并且同域訪(fǎng)問(wèn)時(shí)會(huì)自動(dòng)帶上
Connection: 當(dāng)瀏覽器與服務(wù)器通信時(shí)對(duì)于長(zhǎng)連接如何進(jìn)行處理,如keep-alive
Host:請(qǐng)求的服務(wù)器URL
Origin:最初的請(qǐng)求是從哪里發(fā)起的(只會(huì)精確到端口),Origin比Referer更尊重隱私
Referer:該頁(yè)面的來(lái)源URL(適用于所有類(lèi)型的請(qǐng)求,會(huì)精確到詳細(xì)頁(yè)面地址,csrf攔截常用到這個(gè)字段)
User-Agent:用戶(hù)客戶(hù)端的一些必要信息,如UA頭部等
6. 瀏覽器接收服務(wù)器的響
服務(wù)器在收到瀏覽器發(fā)送的HTTP請(qǐng)求之后,會(huì)將收到的HTTP報(bào)文封裝成HTTP的Request對(duì)象,并通過(guò)不同的Web服務(wù)器進(jìn)行處理,處理完的結(jié)果以HTTP的Response對(duì)象返回,主要包括狀態(tài)碼,響應(yīng)頭,響應(yīng)報(bào)文三個(gè)部分。
狀態(tài)碼主要包括以下部分
- 1xx:指示信息–表示請(qǐng)求已接收,繼續(xù)處理。
- 2xx:成功–表示請(qǐng)求已被成功接收、理解、接受。
- 3xx:重定向–要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作。
- 4xx:客戶(hù)端錯(cuò)誤–請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)。
- 5xx:服務(wù)器端錯(cuò)誤–服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求。
響應(yīng)頭主要由Cache-Control、 Connection、Date、Pragma等組成。
響應(yīng)體為服務(wù)器返回給瀏覽器的信息,主要由HTML,css,js,圖片文件組成。
常用的響應(yīng)頭部(部分):
Access-Control-Allow-Headers: 服務(wù)器端允許的請(qǐng)求Headers
Access-Control-Allow-Methods: 服務(wù)器端允許的請(qǐng)求方法
Access-Control-Allow-Origin: 服務(wù)器端允許的請(qǐng)求Origin頭部(譬如為*)
Content-Type:服務(wù)端返回的實(shí)體內(nèi)容的類(lèi)型
Date:數(shù)據(jù)從服務(wù)器發(fā)送的時(shí)間
Cache-Control:告訴瀏覽器或其他客戶(hù),什么環(huán)境可以安全的緩存文檔
Last-Modified:請(qǐng)求資源的最后修改時(shí)間
Expires:應(yīng)該在什么時(shí)候認(rèn)為文檔已經(jīng)過(guò)期,從而不再緩存它
Max-age:客戶(hù)端的本地資源應(yīng)該緩存多少秒,開(kāi)啟了Cache-Control后有效
ETag:請(qǐng)求變量的實(shí)體標(biāo)簽的當(dāng)前值
Set-Cookie:設(shè)置和頁(yè)面關(guān)聯(lián)的cookie,服務(wù)器通過(guò)這個(gè)頭部把cookie傳給客戶(hù)端
Keep-Alive:如果客戶(hù)端有keep-alive,服務(wù)端也會(huì)有響應(yīng)(如timeout=38)
Server:服務(wù)器的一些相關(guān)信息
如下圖是對(duì)某請(qǐng)求的http報(bào)文結(jié)構(gòu)的簡(jiǎn)要分析

7. 頁(yè)面渲染
前面有提到http交互,那么接下來(lái)就是瀏覽器獲取到html,然后解析,渲染
- 解析HTML,構(gòu)建DOM樹(shù)
- 解析CSS,生成CSS規(guī)則樹(shù)
- 合并DOM樹(shù)和CSS規(guī)則,生成render樹(shù)
- 布局render樹(shù)(Layout/reflow),負(fù)責(zé)各元素尺寸、位置的計(jì)算
- 繪制render樹(shù)(paint),繪制頁(yè)面像素信息
-
瀏覽器會(huì)將各層的信息發(fā)送給GPU,GPU會(huì)將各層合成(composite),顯示在屏幕上
如下圖:
頁(yè)面渲染.png
DOM樹(shù).png
CSSOM樹(shù).png
- 在瀏覽器還沒(méi)接收到完整的 HTML 文件時(shí),它就開(kāi)始渲染頁(yè)面了,在遇到外部鏈入的腳本標(biāo)簽或樣式標(biāo)簽或圖片時(shí),會(huì)再次發(fā)送 HTTP 請(qǐng)求重復(fù)上述的步驟。在收到 CSS 文件后會(huì)對(duì)已經(jīng)渲染的頁(yè)面重新渲染,加入它們應(yīng)有的樣式,圖片文件加載完立刻顯示在相應(yīng)位置。在這一過(guò)程中可能會(huì)觸發(fā)頁(yè)面的重繪或重排。這里就涉及了兩個(gè)重要概念:Reflow和Repaint。
- Reflow,也稱(chēng)作Layout,中文叫回流,一般意味著元素的內(nèi)容、結(jié)構(gòu)、位置或尺寸發(fā)生了變化,需要重新計(jì)算樣式和渲染樹(shù),這個(gè)過(guò)程稱(chēng)為Reflow。
- Repaint,中文重繪,意味著元素發(fā)生的改變只是影響了元素的一些外觀之類(lèi)的時(shí)候(例如,背景色,邊框顏色,文字顏色等),此時(shí)只需要應(yīng)用新樣式繪制這個(gè)元素就OK了,這個(gè)過(guò)程稱(chēng)為Repaint。
- 所以說(shuō)Reflow的成本比Repaint的成本高得多的多。DOM樹(shù)里的每個(gè)結(jié)點(diǎn)都會(huì)有reflow方法,一個(gè)結(jié)點(diǎn)的reflow很有可能導(dǎo)致子結(jié)點(diǎn),甚至父點(diǎn)以及同級(jí)結(jié)點(diǎn)的reflow。
8. 關(guān)閉TCP連接或繼續(xù)保持連接
通過(guò)四次揮手關(guān)閉連接(FIN ACK, ACK, FIN ACK, ACK)。

- 第一次揮手是瀏覽器發(fā)完數(shù)據(jù)后,發(fā)送FIN請(qǐng)求斷開(kāi)連接。
- 第二次揮手是服務(wù)器發(fā)送ACK表示同意,如果在這一次服務(wù)器也發(fā)送FIN請(qǐng)求斷開(kāi)連接似乎也沒(méi)有不妥,但考慮到服務(wù)器可能還有數(shù)據(jù)要發(fā)送,所以服務(wù)器發(fā)送FIN應(yīng)該放在第三次揮手中。
- 這樣瀏覽器需要返回ACK表示同意,也就是第四次揮手。


