也許大多數(shù)人使用 Chrome 最多的場景就是在地址欄輸入關(guān)鍵字進(jìn)行搜索或者輸入地址導(dǎo)航到某個(gè)網(wǎng)站,我們來看看瀏覽器是怎么看待這個(gè)過程的。我們知道瀏覽器 Tab 外的工作主要由 Browser Process 掌控,Browser Process 又對(duì)這些工作進(jìn)一步劃分,使用不同線程進(jìn)行處理:
確認(rèn)導(dǎo)航進(jìn)過了上述過程,數(shù)據(jù)以及渲染進(jìn)程都可用了, Browser Process 會(huì)給 renderer process 發(fā)送 IPC 消息來確認(rèn)導(dǎo)航,一旦 Browser Process 收到 renderer process 的渲染確認(rèn)消息,導(dǎo)航過程結(jié)束,頁面加載過程開始。此時(shí),地址欄會(huì)更新,展示出新頁面的網(wǎng)頁信息。history tab 會(huì)更新,可通過返回鍵返回導(dǎo)航來的頁面,為了讓關(guān)閉 tab 或者窗口后便于恢復(fù),這些信息會(huì)存放在硬盤中。 Browser Process 和 Renderer Process 通過 IPC 通信,請(qǐng)求 Renderer Process 渲染頁面額外的步驟一旦導(dǎo)航被確認(rèn),renderer process 會(huì)使用相關(guān)的資源渲染頁面,下文中我們將重點(diǎn)介紹渲染流程。當(dāng) renderer process 渲染結(jié)束(渲染結(jié)束意味著該頁面內(nèi)的所有的頁面,包括所有 iframe 都觸發(fā)了 onload 時(shí)),會(huì)發(fā)送 IPC 信號(hào)到 Browser process, UI thread 會(huì)停止展示 tab 中的 spinner。Renderer Process 發(fā)送 IPC 消息通知 browser process 頁面已經(jīng)加載完成當(dāng)然上面的流程只是網(wǎng)頁首幀渲染完成,在此之后,客戶端依舊可下載額外的資源渲染出新的視圖。在這里我們可以明確一點(diǎn),所有的 JS 代碼其實(shí)都由 renderer Process 控制的,所以在你瀏覽網(wǎng)頁內(nèi)容的過程大部分時(shí)候不會(huì)涉及到其它的進(jìn)程。不過也許你也曾經(jīng)監(jiān)聽過?beforeunload?事件,這個(gè)事件再次涉及到 Browser Process 和 renderer Process 的交互,當(dāng)當(dāng)前頁面關(guān)閉時(shí)(關(guān)閉 Tab ,刷新等等),Browser Process 需要通知 renderer Process 進(jìn)行相關(guān)的檢查,對(duì)相關(guān)事件進(jìn)行處理。瀏覽器進(jìn)程發(fā)送 IPC 消息給渲染進(jìn)程,通知要離開當(dāng)前網(wǎng)站了如果導(dǎo)航由 renderer process 觸發(fā)(比如在用戶點(diǎn)擊某鏈接,或者JS執(zhí)行?window.location = http://newsite.com?) renderer process 會(huì)首先檢查是否有?beforeunload?事件處理器,導(dǎo)航請(qǐng)求由 renderer process 傳遞給 Browser process如果導(dǎo)航到新的網(wǎng)站,會(huì)啟用一個(gè)新的 render process 來處理新頁面的渲染,老的進(jìn)程會(huì)留下來處理類似?unload?等事件。關(guān)于頁面的生命周期,更多內(nèi)容可參考 Page Lifecycle API 。瀏覽器進(jìn)程發(fā)送 IPC 消息到新的渲染進(jìn)程通知渲染新的頁面,同時(shí)通知舊的渲染進(jìn)程卸載除了上述流程,有些頁面還擁有 Service Worker (服務(wù)工作線程),Service Worker 讓開發(fā)者對(duì)本地緩存及判斷何時(shí)從網(wǎng)絡(luò)上獲取信息有了更多的控制權(quán),如果 Service Worker 被設(shè)置為從本地 cache 中加載數(shù)據(jù),那么就沒有必要從網(wǎng)上獲取更多數(shù)據(jù)了。值得注意的是 service worker 也是運(yùn)行在渲染進(jìn)程中的 JS 代碼,因此對(duì)于擁有 Service Worker 的頁面,上述流程有些許的不同。當(dāng)有 Service Worker 被注冊(cè)時(shí),其作用域會(huì)被保存,當(dāng)有導(dǎo)航時(shí),network thread 會(huì)在注冊(cè)過的 Service Worker 的作用域中檢查相關(guān)域名,如果存在對(duì)應(yīng)的 Service worker,UI thread 會(huì)找到一個(gè) renderer process 來處理相關(guān)代碼,Service Worker 可能會(huì)從 cache 中加載數(shù)據(jù),從而終止對(duì)網(wǎng)絡(luò)的請(qǐng)求,也可能從網(wǎng)上請(qǐng)求新的數(shù)據(jù)。Service Worker 依據(jù)具體情形做處理關(guān)于 Service Worker 的更多內(nèi)容可參考?The Service Worker Lifecycle如果 Service Worker 最終決定通過網(wǎng)上獲取數(shù)據(jù),Browser 進(jìn)程 和 renderer 進(jìn)程的交互其實(shí)會(huì)延后數(shù)據(jù)的請(qǐng)求時(shí)間 。Navigation Preload 是一種與 Service Worker 并行的加速加載資源的機(jī)制,服務(wù)端通過請(qǐng)求頭可以識(shí)別這類請(qǐng)求,而做出相應(yīng)的處理。更多內(nèi)容可參考:Speed up Service Worker with Navigation Preloads
渲染進(jìn)程是如何工作的
渲染進(jìn)程幾乎負(fù)責(zé) Tab 內(nèi)的所有事情,渲染進(jìn)程的核心目的在于轉(zhuǎn)換 HTML CSS JS 為用戶可交互的 web 頁面。渲染進(jìn)程中主要包含以下線程:渲染進(jìn)程包含的線程
主線程 Main thread
工作線程 Worker thread
排版線程 Compositor thread
光柵線程 Raster thread
后文我們將逐步介紹不同線程的職責(zé),在此之前我們先看看渲染的流程
構(gòu)建 DOM
當(dāng)渲染進(jìn)程接收到導(dǎo)航的確認(rèn)信息,開始接受 HTML 數(shù)據(jù)時(shí),主線程會(huì)解析文本字符串為 DOM。渲染 html 為 DOM 的方法由 HTML Standard 定義。
加載次級(jí)的資源
網(wǎng)頁中常常包含諸如圖片,CSS,JS 等額外的資源,這些資源需要從網(wǎng)絡(luò)上或者 cache 中獲取。主進(jìn)程可以在構(gòu)建 DOM 的過程中會(huì)逐一請(qǐng)求它們,為了加速 preload scanner 會(huì)同時(shí)運(yùn)行,如果在 html 中存在???等標(biāo)簽,preload scanner 會(huì)把這些請(qǐng)求傳遞給 Browser process 中的 network thread 進(jìn)行相關(guān)資源的下載。