當你在瀏覽器中輸入google.com并且按下回車之后發(fā)生了什么?
來源:易賢網(wǎng) 閱讀:1755 次 日期:2015-04-02 14:04:08
溫馨提示:易賢網(wǎng)小編為您整理了“當你在瀏覽器中輸入google.com并且按下回車之后發(fā)生了什么?”,方便廣大網(wǎng)友查閱!

本文試圖回答一個古老的面試問題:當你在瀏覽器中輸入google.com并且按下回車之后發(fā)生了什么?

不過我們不再局限于平常的回答,而是想辦法回答地盡可能具體,不遺漏任何細節(jié)。

這將是一個協(xié)作的過程,所以深入挖掘吧,并且?guī)椭覀円黄鹜晟扑H匀挥写罅康募毠?jié)等待著你來添加,歡迎向我們發(fā)送Pull Requset!

這些內(nèi)容使用 Creative Commons Zero 協(xié)議發(fā)布。

回車鍵按下

為了從頭開始,我們選擇鍵盤上的回車鍵被按到最低處作為起點。在這個時刻,一個專用于回車鍵的電流回路被直接或者通過電容器閉合了,使得少量的電流進入了鍵盤的邏輯電路系統(tǒng)。這個系統(tǒng)會掃描每個鍵的狀態(tài),對于按鍵開關(guān)的電位彈跳變化進行噪音消除(debounce),并將其轉(zhuǎn)化為鍵盤碼值。在這里,回車的碼值是13。鍵盤控制器在得到碼值之后,將其編碼,用于之后的傳輸。現(xiàn)在這個傳輸過程幾乎都是通過通用串行總線(USB)或者藍牙(Bluetooth)來進行的,以前是通過PS/2或者ADB連接進行。

USB鍵盤:

鍵盤的USB元件通過計算機上的USB接口與USB控制器相連接,USB接口中的第一號針為它提供了5V的電壓

鍵碼值存儲在鍵盤內(nèi)部電路一個叫做”endpoint”的寄存器內(nèi)

USB控制器大概每隔10ms便查詢一次”endpoint”以得到存儲的鍵碼值數(shù)據(jù),這個最短時間間隔由鍵盤提供

鍵值碼值通過USB串行接口引擎被轉(zhuǎn)換成一個或者多個遵循低層USB協(xié)議的USB數(shù)據(jù)包

這些數(shù)據(jù)包通過D+針或者D-針(中間的兩個針),以最高1.5Mb/s的速度從鍵盤傳輸至計算機。速度限制是因為人機交互設(shè)備總是被聲明成”低速設(shè)備”(USB 2.0 compliance)

這個串行信號在計算機的USB控制器處被解碼,然后被人機交互設(shè)備通用鍵盤驅(qū)動進行進一步解釋。之后按鍵的碼值被傳輸?shù)讲僮飨到y(tǒng)的硬件抽象層

虛擬鍵盤(觸屏設(shè)備):

在現(xiàn)代電容屏上,當用戶把手指放在屏幕上時,一小部分電流從傳導(dǎo)層的靜電域經(jīng)過手指傳導(dǎo),形成了一個回路,使得屏幕上觸控的那一點電壓下降,屏幕控制器產(chǎn)生一個中斷,報告這次“點擊”的坐標

然后移動操作系統(tǒng)通知當前活躍的應(yīng)用,有一個點擊事件發(fā)生在它的某個GUI部件上了,現(xiàn)在這個部件是虛擬鍵盤的按鈕

虛擬鍵盤引發(fā)一個軟中斷,返回給OS一個“按鍵按下”消息

這個消息又返回來向當前活躍的應(yīng)用通知一個“按鍵按下”事件

產(chǎn)生中斷[非USB鍵盤]

鍵盤在它的中斷請求線(IRQ)上發(fā)送信號,信號會被中斷控制器映射到一個中斷向量,實際上就是一個整型數(shù) 。CPU使用中斷描述符表(IDT)把中斷向量映射到對應(yīng)函數(shù),這些函數(shù)被稱為中斷處理器,它們由操作系統(tǒng)內(nèi)核提供。當一個中斷到達時,CPU根據(jù)IDT和中斷向量索引到對應(yīng)的中端處理器,然后操作系統(tǒng)內(nèi)核出場了。

(Windows)一個 WM_KEYDOWN 消息被發(fā)往應(yīng)用程序

HID把鍵盤按下的事件傳送給 KBDHID.sys 驅(qū)動,把HID的信號轉(zhuǎn)換成一個掃描碼(Scancode),這里回車的掃描碼是 VK_RETURN(0x0d)。 KBDHID.sys 驅(qū)動和 KBDCLASS.sys (鍵盤類驅(qū)動,keyboard class driver)進行交互,這個驅(qū)動負責安全地處理所有鍵盤和小鍵盤的輸入事件。之后它又去調(diào)用 Win32K.sys ,在這之前有可能把消息傳遞給安裝的第三方鍵盤過濾器。這些都是發(fā)生在內(nèi)核模式。

Win32K.sys 通過 GetForegroundWindow() API函數(shù)找到當前哪個窗口是活躍的。這個API函數(shù)提供了當前瀏覽器的地址欄的句柄。Windows系統(tǒng)的”message pump”機制調(diào)用 SendMessage(hWnd, WM_KEYDOWN, VK_RETURN, lParam) 函數(shù), lParam 是一個用來指示這個按鍵的更多信息的掩碼,這些信息包括按鍵重復(fù)次數(shù)(這里是0),實際掃描碼(可能依賴于OEM廠商,不過通常不會是 VK_RETURN ),功能鍵(alt, shift, ctrl)是否被按下(在這里沒有),以及一些其他狀態(tài)。

Windows的 SendMessage API直接將消息添加到特定窗口句柄 hWnd 的消息隊列中,之后賦給 hWnd 的主要消息處理函數(shù) WindowProc 將會被調(diào)用,用于處理隊列中的消息。

當前活躍的句柄 hWnd 實際上是一個edit control控件,這種情況下,WindowProc 有一個用于處理WM_KEYDOWN 消息的處理器,這段代碼會查看 SendMessage 傳入的第三個參數(shù) wParam ,因為這個參數(shù)是 VK_RETURN ,于是它知道用戶按下了回車鍵。

(Mac OS X)一個 KeyDown NSEvent被發(fā)往應(yīng)用程序

中斷信號引發(fā)了I/O Kit Kext鍵盤驅(qū)動的中斷處理事件,驅(qū)動把信號翻譯成鍵碼值,然后傳給OS X的WindowServer 進程。然后, WindowServer 將這個事件通過Mach端口分發(fā)給合適的(活躍的,或者正在監(jiān)聽的)應(yīng)用程序,這個信號會被放到應(yīng)用程序的消息隊列里。隊列中的消息可以被擁有足夠高權(quán)限的線程使用 mach_ipc_dispatch 函數(shù)讀取到。這個過程通常是由 NSApplication 主事件循環(huán)產(chǎn)生并且處理的,通過 NSEventType 為 KeyDown 的 NSEvent 。

(GNU/Linux)Xorg 服務(wù)器監(jiān)聽鍵碼值

當使用圖形化的 X Server 時,X Server會按照特定的規(guī)則把鍵碼值再一次映射,映射成掃描碼。當這個映射過程完成之后, X Server 把這個按鍵字符發(fā)送給窗口管理器(DWM,metacity, i3等等),窗口管理器再把字符發(fā)送給當前窗口。當前窗口使用有關(guān)圖形API把文字打印在輸入框內(nèi)。

解析URL

瀏覽器通過URL能夠知道下面的信息:

Protocol ”http”

使用HTTP協(xié)議

Resource ”/”

請求的資源是主頁(index)

輸入的是URL還是搜索的關(guān)鍵字?

當協(xié)議或主機名不合法時,瀏覽器會將地址欄中輸入的文字傳給默認的搜索引擎。大部分情況下,在把文字傳遞給搜索引擎的時候,URL會帶有特定的一串字符,用來告訴搜索引擎這次搜索來自這個特定瀏覽器。

檢查HSTS列表···

瀏覽器檢查自帶的“預(yù)加載HSTS(HTTP嚴格傳輸安全)”列表,這個列表里包含了那些請求瀏覽器只使用HTTPS進行連接的網(wǎng)站

如果網(wǎng)站在這個列表里,瀏覽器會使用HTTPS而不是HTTP協(xié)議,否則,最初的請求會使用HTTP協(xié)議發(fā)送

注意,一個網(wǎng)站哪怕不在HSTS列表里,也可以要求瀏覽器對自己使用HSTS政策進行訪問。瀏覽器向網(wǎng)站發(fā)出第一個HTTP請求之后,網(wǎng)站會返回瀏覽器一個響應(yīng),請求瀏覽器只使用HTTPS發(fā)送請求。然而,就是這第一個HTTP請求,卻可能會使用戶收到 downgrade attack 的威脅,這也是為什么現(xiàn)代瀏覽器都預(yù)置了HSTS列表。

轉(zhuǎn)換非ASCII的Unicode字符

瀏覽器檢查輸入是否含有不是 a-z, A-Z,0-9, - 或者 . 的字符

這里主機名是 google.com ,所以沒有非ASCII的字符,如果有的話,瀏覽器會對主機名部分使用Punycode 編碼

DNS查詢···

瀏覽器檢查域名是否在緩存當中

如果緩存中沒有,就去調(diào)用 gethostbynme 庫函數(shù)(操作系統(tǒng)不同函數(shù)也不同)進行查詢

gethostbyname 函數(shù)在試圖進行DNS解析之前首先檢查域名是否在本地Hosts里,Hosts的位置 不同的操作系統(tǒng)有所不同

如果 gethostbyname 沒有這個域名的緩存記錄,也沒有在 hosts 里找到,它將會向DNS 服務(wù)器發(fā)送一條DNS查詢請求。DNS服務(wù)器是由網(wǎng)絡(luò)通信棧提供的,通常是本地路由器或者ISP的緩存DNS服務(wù)器。

查詢本地 DNS 服務(wù)器

如果DNS服務(wù)器和我們的主機在同一個子網(wǎng)內(nèi),系統(tǒng)會按照下面的 ARP 過程對 DNS 服務(wù)器進行 ARP查詢

如果DNS服務(wù)器和我們的主機在不同的子網(wǎng),系統(tǒng)會按照下面的 ARP 過程對默認網(wǎng)關(guān)進行查詢

ARP

要想發(fā)送ARP廣播,我們需要有一個目標IP地址,同時還需要知道用于發(fā)送ARP廣播的接口的Mac地址。

首先查詢ARP緩存,如果緩存命中,我們返回結(jié)果:目標IP = MAC

如果緩存沒有命中:

查看路由表,看看目標IP地址是不是在本地路由表中的某個子網(wǎng)內(nèi)。是的話,使用跟那個子網(wǎng)相連的接口,否則使用與默認網(wǎng)關(guān)相連的接口。

查詢選擇的網(wǎng)絡(luò)接口的MAC地址

我們發(fā)送一個二層ARP請求:

ARP Request:

Sender MAC: interface:mac:address:here

Sender IP: interface.ip.goes.here

Target MAC: FF:FF:FF:FF:FF:FF (Broadcast)

Target IP: target.ip.goes.here

根據(jù)連接主機和路由器的硬件類型不同,可以分為以下幾種情況:

直連:

如果我們和路由器是直接連接的,路由器會返回一個 ARP Reply (見下面)。

集線器:

如果我們連接到一個集線器,集線器會把ARP請求向所有其它端口廣播,如果路由器也“連接”在其中,它會返回一個 ARP Reply 。

交換機:

如果我們連接到了一個交換機,交換機會檢查本地 CAM/MAC 表,看看哪個端口有我們要找的那個MAC地址,如果沒有找到,交換機會向所有其它端口廣播這個ARP請求。

如果交換機的MAC/CAM表中有對應(yīng)的條目,交換機會向有我們想要查詢的MAC地址的那個端口發(fā)送ARP請求

如果路由器也“連接”在其中,它會返回一個 ARP Reply

ARP Reply:

Sender MAC: target:mac:address:here

Sender IP: target.ip.goes.here

Target MAC: interface:mac:address:here

Target IP: interface.ip.goes.here

現(xiàn)在我們有了DNS服務(wù)器或者默認網(wǎng)關(guān)的IP地址,我們可以繼續(xù)DNS請求了:

使用53端口向DNS服務(wù)器發(fā)送UDP請求包,如果響應(yīng)包太大,會使用TCP

如果本地/ISP DNS服務(wù)器沒有找到結(jié)果,它會發(fā)送一個遞歸查詢請求,一層一層向高層DNS服務(wù)器做查詢,直到查詢到起始授權(quán)機構(gòu),如果找到會把結(jié)果返回

使用套接字

當瀏覽器得到了目標服務(wù)器的IP地址,以及URL中給出來端口號(http協(xié)議默認端口號是80, https默認端口號是443),它會調(diào)用系統(tǒng)庫函數(shù) socket ,請求一個 TCP流套接字,對應(yīng)的參數(shù)是 AF_INET 和SOCK_STREAM 。

這個請求首先被交給傳輸層,在傳輸層請求被封裝成TCP segment。目標端口會會被加入頭部,源端口會在系統(tǒng)內(nèi)核的動態(tài)端口范圍內(nèi)選?。↙inux下是ip_local_port_range)

TCP segment被送往網(wǎng)絡(luò)層,網(wǎng)絡(luò)層會在其中再加入一個IP頭部,里面包含了目標服務(wù)器的IP地址以及本機的IP地址,把它封裝成一個TCP packet。

這個TCP packet接下來會進入鏈路層,鏈路層會在封包中加入frame頭部,里面包含了本地內(nèi)置網(wǎng)卡的MAC地址以及網(wǎng)關(guān)(本地路由器)的MAC地址。像前面說的一樣,如果內(nèi)核不知道網(wǎng)關(guān)的MAC地址,它必須進行ARP廣播來查詢其地址。

到了現(xiàn)在,TCP封包已經(jīng)準備好了,可是使用下面的方式進行傳輸:

以太網(wǎng)

WiFi

蜂窩數(shù)據(jù)網(wǎng)絡(luò)

對于大部分家庭網(wǎng)絡(luò)和小型企業(yè)網(wǎng)絡(luò)來說,封包會從本地計算機出發(fā),經(jīng)過本地網(wǎng)絡(luò),再通過調(diào)制解調(diào)器把數(shù)字信號轉(zhuǎn)換成模擬信號,使其適于在電話線路,有線電視光纜和無線電話線路上傳輸。在傳輸線路的另一端,是另外一個調(diào)制解調(diào)器,它把模擬信號轉(zhuǎn)換回數(shù)字信號,交由下一個 網(wǎng)絡(luò)節(jié)點 處理。節(jié)點的目標地址和源地址將在后面討論。

大型企業(yè)和比較新的住宅通常使用光纖或直接以太網(wǎng)連接,這種情況下信號一直是數(shù)字的,會被直接傳到下一個 網(wǎng)絡(luò)節(jié)點 進行處理。

最終封包會到達管理本地子網(wǎng)的路由器。在那里出發(fā),它會繼續(xù)經(jīng)過自治區(qū)域的邊界路由器,其他自治區(qū)域,最終到達目標服務(wù)器。一路上經(jīng)過的這些路由器會從IP數(shù)據(jù)報頭部里提取出目標地址,并將封包正確地路由到下一個目的地。IP數(shù)據(jù)報頭部TTL域的值每經(jīng)過一個路由器就減1,如果封包的TTL變?yōu)?,或者路由器由于網(wǎng)絡(luò)擁堵等原因封包隊列滿了,那么這個包會被路由器丟棄。

上面的發(fā)送和接受過程在TCP連接期間會發(fā)生很多次:

客戶端選擇一個初始序列號(ISN),將設(shè)置了SYN位的封包發(fā)送給服務(wù)器端,表明自己要建立連接并設(shè)置了初始序列號

服務(wù)器端接受到SYN包,如果它可以建立連接:

服務(wù)器端選擇它自己的初始序列號

服務(wù)器端設(shè)置SYN位,表明自己選擇了一個初始序列號

服務(wù)器端把 (客戶端ISN + 1) 復(fù)制到ACK域,并且設(shè)置ACK位,表明自己接收到了客戶端的第一個封包

客戶端通過發(fā)送下面一個封包來確認這次連接:

自己的序列號+1

接收端ACK+1

設(shè)置ACK位

數(shù)據(jù)通過下面的方式傳輸:

當一方發(fā)送了N個Bytes的數(shù)據(jù)之后,將自己的SEQ序列號也增加N

另一方確認接收到這個數(shù)據(jù)包(或者一系列數(shù)據(jù)包)之后,它發(fā)送一個ACK包,ACK的值設(shè)置為接收到的數(shù)據(jù)包的最后一個序列號

關(guān)閉連接時:

要關(guān)閉連接的一方發(fā)送一個FIN包

另一方確認這個FIN包,并且發(fā)送自己的FIN包

要關(guān)閉的一方使用ACK包來確認接收到了FIN

UDP 數(shù)據(jù)包

TLS 握手

客戶端發(fā)送一個 Client hello 消息到服務(wù)器端,消息中同時包含了它的TLS版本,可用的加密算法和壓縮算法。

服務(wù)器端向客戶端返回一個 Server hello 消息,消息中包含了服務(wù)器端的TLS版本,服務(wù)器選擇了哪個加密和壓縮算法,以及服務(wù)器的公開證書,證書中包含了公鑰??蛻舳藭褂眠@個公鑰加密接下來的握手過程,直到協(xié)商生成一個新的對稱密鑰

客戶端根據(jù)自己的信任CA列表,驗證服務(wù)器端的證書是否有效。如果有效,客戶端會生成一串偽隨機數(shù),使用服務(wù)器的公鑰加密它。這串隨機數(shù)會被用于生成新的對稱密鑰

服務(wù)器端使用自己的私鑰解密上面提到的隨機數(shù),然后使用這串隨機數(shù)生成自己的對稱主密鑰

客戶端發(fā)送一個 Finished 消息給服務(wù)器端,使用對稱密鑰加密這次通訊的一個散列值

服務(wù)器端生成自己的 hash 值,然后解密客戶端發(fā)送來的信息,檢查這兩個值是否對應(yīng)。如果對應(yīng),就向客戶端發(fā)送一個 Finished 消息,也使用協(xié)商好的對稱密鑰加密

從現(xiàn)在開始,接下來整個 TLS 會話都使用對稱秘鑰進行加密,傳輸應(yīng)用層(HTTP)內(nèi)容

TCP 數(shù)據(jù)包

HTTP 協(xié)議···

如果瀏覽器是Google出品的,它不會使用HTTP協(xié)議來獲取頁面信息,而是會與服務(wù)器端發(fā)送請求,商討使用SPDY協(xié)議。

如果瀏覽器使用HTTP協(xié)議,它會向服務(wù)器發(fā)送這樣的一個請求:

GET / HTTP/1.1

Host: google.com

[其他頭部]

“其他頭部”包含了一系列的由冒號分割開的鍵值對,它們的格式符合HTTP協(xié)議標準,它們之間由一個換行符分割開來。這里我們假設(shè)瀏覽器沒有違反HTTP協(xié)議標準的bug,同時瀏覽器使用 HTTP/1.1 協(xié)議,不然的話頭部可能不包含 Host 字段,同時 GET 請求中的版本號會變成 HTTP/1.0 或者 HTTP/0.9 。

HTTP/1.1 定義了“關(guān)閉連接”的選項 “close”,發(fā)送者使用這個選項指示這次連接在響應(yīng)結(jié)束之后會斷開:

Connection:close

不支持持久連接的 HTTP/1.1 必須在每條消息中都包含 “close” 選項。

在發(fā)送完這些請求和頭部之后,瀏覽器發(fā)送一個換行符,表示要發(fā)送的內(nèi)容已經(jīng)結(jié)束了。

服務(wù)器端返回一個響應(yīng)碼,指示這次請求的狀態(tài),響應(yīng)的形式是這樣的:

200 OK

[response headers]

然后是一個換行,接下來有效載荷(payload),也就是 的HTML內(nèi)容。服務(wù)器下面可能會關(guān)閉連接,如果客戶端請求保持連接的話,服務(wù)器端會保持連接打開,以供以后的請求重用。

如果瀏覽器發(fā)送的HTTP頭部包含了足夠多的信息(例如包含了 Etag 頭部,以至于服務(wù)器可以判斷出,瀏覽器緩存的文件版本自從上次獲取之后沒有再更改過,服務(wù)器可能會返回這樣的響應(yīng):

304 Not Modified

[response headers]

這個響應(yīng)沒有有效載荷,瀏覽器會從自己的緩存中取出想要的內(nèi)容。

在解析完HTML之后,瀏覽器和客戶端會重復(fù)上面的過程,直到HTML頁面引入的所有資源(圖片,CSS,favicon.ico等等)全部都獲取完畢,區(qū)別只是頭部的 GET / HTTP/1.1 會變成 GET /$(相對的URL) HTTP/1.1 。

如果HTML引入了域名之外的資源,瀏覽器會回到上面解析域名那一步,按照下面的步驟往下一步一步執(zhí)行,請求中的 Host 頭部會變成另外的域名。

HTTP服務(wù)器請求處理

HTTPD(HTTP Daemon)在服務(wù)器端處理請求/相應(yīng)。最常見的 HTTPD 有 Linux 上常用的 Apache 和 nginx,與 Windows 上的 IIS。

HTTPD接收請求

服務(wù)器把請求拆分為以下幾個參數(shù):

HTTP請求方法(GET, POST, HEAD, PUT 和 DELETE )。在訪問Google這種情況下,使用的是GET方法

域名:google.com

請求路徑/頁面:/ (我們沒有請求google.com下的指定的頁面,因此 / 是默認的路徑)

服務(wù)器驗證其上已經(jīng)配置了google.com的虛擬主機

服務(wù)器驗證google.com接受GET方法

服務(wù)器驗證該用戶可以使用GET方法(根據(jù)IP地址,身份信息等)

如果服務(wù)器安裝了 URL 重寫模塊(例如 Apache 的 mod_rewrite 和 IIS 的 URL Rewrite),服務(wù)器會嘗試匹配重寫規(guī)則,如果匹配上的話,服務(wù)器會按照規(guī)則重寫這個請求

服務(wù)器根據(jù)請求信息獲取相應(yīng)的響應(yīng)內(nèi)容,這種情況下由于訪問路徑是 “/” ,會訪問首頁文件。(你可以重寫這個規(guī)則,但是這個是最常用的)

服務(wù)器會使用指定的處理程序分析處理這個文件,比如假設(shè)Google使用PHP,服務(wù)器會使用PHP解析index文件,并捕獲輸出,把PHP的輸出結(jié)果給請求者

瀏覽器背后的故事

當服務(wù)器提供了資源之后(HTML,CSS,JS,圖片等),瀏覽器會執(zhí)行下面的操作:

解析 HTML,CSS,JS

渲染——構(gòu)建 DOM 樹 -> 渲染 -> 布局 -> 繪制

瀏覽器

瀏覽器的功能是從服務(wù)器上取回你想要的資源,然后展示在瀏覽器窗口當中。資源通常是 HTML 文件,也可能是 PDF,圖片,或者其他類型的內(nèi)容。資源的位置通過用戶提供的 URI(Uniform Resource Identifier) 來確定。

瀏覽器解釋和展示 HTML 文件的方法,在 HTML 和 CSS 的標準中有詳細介紹。這些標準由 Web 標準組織 W3C(World Wide Web Consortium) 維護。

不同瀏覽器的用戶界面大都十分接近,有很多共同的 UI 元素:

一個地址欄

后退和前進按鈕

書簽選項

刷新和停止按鈕

主頁按鈕

瀏覽器高層架構(gòu)

組成瀏覽器的組件有:

用戶界面 用戶界面包含了地址欄,前進后退按鈕,書簽菜單等等,除了請求頁面之外所有你看到的內(nèi)容都是用戶界面的一部分

瀏覽器引擎 瀏覽器引擎負責讓 UI 和渲染引擎協(xié)調(diào)工作

渲染引擎 渲染引擎負責展示請求內(nèi)容。如果請求的內(nèi)容是 HTML,渲染引擎會解析 HTML 和 CSS,然后將內(nèi)容展示在屏幕上

網(wǎng)絡(luò)組件 網(wǎng)絡(luò)組件負責網(wǎng)絡(luò)調(diào)用,例如 HTTP 請求等,使用一個平臺無關(guān)接口,下層是針對不同平臺的具體實現(xiàn)

UI后端 UI后端用于繪制基本 UI 組件,例如下拉列表框和窗口。UI 后端暴露一個統(tǒng)一的平臺無關(guān)的接口,下層使用操作系統(tǒng)的 UI 方法實現(xiàn)

Javascript 解釋器 Javascript 解釋器用于解析和執(zhí)行 Javascript 代碼

數(shù)據(jù)存儲 數(shù)據(jù)存儲組件是一個持久層。瀏覽器可能需要在本地存儲各種各樣的數(shù)據(jù),例如 Cookie 等。瀏覽器也需要支持諸如 localStorage,IndexedDB,WebSQL 和 FileSystem 之類的存儲機制

HTML 解析

瀏覽器渲染引擎從網(wǎng)絡(luò)層取得請求的文檔,一般情況下文檔會分成8kB大小的分塊傳輸。

HTML解析器的主要工作是對HTML文檔進行解析,生成解析樹。

解析樹是以DOM元素以及屬性為節(jié)點的樹。DOM是文檔對象模型(Document Object Model)的縮寫,它是HTML文檔的對象表示,同時也是HTML元素面向外部(如Javascript)的接口。樹的根部是”Document”對象。整個DOM和HTML文檔幾乎是一對一的關(guān)系。

解析算法

HTML不能使用常見的自頂向下或自底向上方法來進行分析。主要原因有以下幾點:

語言本身的“寬容”特性

HTML本身可能是殘缺的,對于常見的殘缺,瀏覽器需要有傳統(tǒng)的容錯機制來支持它們

解析過程需要反復(fù)。對于其他語言來說,源碼不會在解析過程中發(fā)生變化,但是對于HTML來說,動態(tài)代碼,例如腳本元素中包含的 document.write() 方法會在源碼中添加內(nèi)容,也就是說,解析過程實際上會改變輸入的內(nèi)容

由于不能使用常用的解析技術(shù),瀏覽器創(chuàng)造了專門用于解析HTML的解析器。解析算法在 HTML5 標準規(guī)范中有詳細介紹,算法主要包含了兩個階段:標記化(tokenization)和樹的構(gòu)建。

解析結(jié)束之后

瀏覽器開始加載網(wǎng)頁的外部資源(CSS,圖像,Javascript 文件等)。

此時瀏覽器把文檔標記為“可交互的”,瀏覽器開始解析處于“推遲”模式的腳本,也就是那些需要在文檔解析完畢之后再執(zhí)行的腳本。之后文檔的狀態(tài)會變?yōu)椤巴瓿伞?,瀏覽器會進行“加載”事件。

注意解析 HTML 網(wǎng)頁時永遠不會出現(xiàn)“語法錯誤”,瀏覽器會修復(fù)所有錯誤,然后繼續(xù)解析。

執(zhí)行同步 Javascript 代碼。

CSS 解析

根據(jù) CSS詞法和句法 分析CSS文件和 <style> 標簽包含的內(nèi)容

每個CSS文件都被解析成一個樣式表對象,這個對象里包含了帶有選擇器的CSS規(guī)則,和對應(yīng)CSS語法的對象

CSS解析器可能是自頂向下的,也可能是使用解析器生成器生成的自底向上的解析器

頁面渲染

通過遍歷DOM節(jié)點樹創(chuàng)建一個“Frame 樹”或“渲染樹”,并計算每個節(jié)點的各個CSS樣式值

通過累加子節(jié)點的寬度,該節(jié)點的水平內(nèi)邊距(padding)、邊框(border)和外邊距(margin),自底向上的計算”Frame 樹”中每個節(jié)點首的選(preferred)寬度

通過自頂向下的給每個節(jié)點的子節(jié)點分配可行寬度,計算每個節(jié)點的實際寬度

通過應(yīng)用文字折行、累加子節(jié)點的高度和此節(jié)點的內(nèi)邊距(padding)、邊框(border)和外邊距(margin),自底向上的計算每個節(jié)點的高度

使用上面的計算結(jié)果構(gòu)建每個節(jié)點的坐標

當存在元素使用 floated,位置有 absolutely 或 relatively 屬性的時候,會有更多復(fù)雜的計算,詳見和

創(chuàng)建layer(層)來表示頁面中的哪些部分可以成組的被繪制,而不用被重新柵格化處理。每個幀對象都被分配給一個層

頁面上的每個層都被分配了紋理(?)

每個層的幀對象都會被遍歷,計算機執(zhí)行繪圖命令繪制各個層,此過程可能由CPU執(zhí)行柵格化處理,或者直接通過D2D/SkiaGL在GPU上繪制

上面所有步驟都可能利用到最近一次頁面渲染時計算出來的各個值,這樣可以減少不少計算量

計算出各個層的最終位置,一組命令由 Direct3D/OpenGL發(fā)出,GPU命令緩沖區(qū)清空,命令傳至GPU并異步渲染,幀被送到Window Server。

GPU 渲染

在渲染過程中,圖形處理層可能使用通用用途的CPU,也可能使用圖形處理器GPU

當使用GPU用于圖形渲染時,圖形驅(qū)動軟件會把任務(wù)分成多個部分,這樣可以充分利用GPU強大的并行計算能力,用于在渲染過程中進行大量的浮點計算。

Window Server

后期渲染與用戶引發(fā)的處理

渲染結(jié)束后,瀏覽器根據(jù)某些時間機制運行JavaScript代碼(比如Google Doodle動畫)或與用戶交互(在搜索欄輸入關(guān)鍵字獲得搜索建議)。類似Flash和Java的插件也會運行,盡管Google主頁里沒有。這些腳本可以觸發(fā)網(wǎng)絡(luò)請求,也可能改變網(wǎng)頁的內(nèi)容和布局,產(chǎn)生又一輪渲染與繪制。

更多信息請查看IT技術(shù)專欄

更多信息請查看技術(shù)文章

2025國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 加入群交流 | 手機站點 | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
咨詢QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)