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

          圖解瀏覽器的基本工作原理

          共 10100字,需瀏覽 21分鐘

           ·

          2020-08-25 05:11

          作者 |?zhangwang
          來源 | https://zhuanlan.zhihu.com/p/47407398
          可能每一個(gè)前端工程師都想要理解瀏覽器的工作原理。
          我們希望知道從在瀏覽器地址欄中輸入 url 到頁面展現(xiàn)的短短幾秒內(nèi)瀏覽器究竟做了什么;
          我們希望了解平時(shí)常常聽說的各種代碼優(yōu)化方案是究竟為什么能起到優(yōu)化的作用;
          我們希望更細(xì)化的了解瀏覽器的渲染流程。

          瀏覽器的多進(jìn)程架構(gòu)

          一個(gè)好的程序常常被劃分為幾個(gè)相互獨(dú)立又彼此配合的模塊,瀏覽器也是如此,以 Chrome 為例,它由多個(gè)進(jìn)程組成,每個(gè)進(jìn)程都有自己核心的職責(zé),它們相互配合完成瀏覽器的整體功能,每個(gè)進(jìn)程中又包含多個(gè)線程,一個(gè)進(jìn)程內(nèi)的多個(gè)線程也會(huì)協(xié)同工作,配合完成所在進(jìn)程的職責(zé)。
          對(duì)一些前端開發(fā)同學(xué)來說,進(jìn)程和線程的概念可能會(huì)有些模糊,為了更好的理解瀏覽器的多進(jìn)程架構(gòu),這里我們簡單討論一下進(jìn)程和線程。
          進(jìn)程(process)和線程(thread)

          進(jìn)程就像是一個(gè)有邊界的生產(chǎn)廠間,而線程就像是廠間內(nèi)的一個(gè)個(gè)員工,可以自己做自己的事情,也可以相互配合做同一件事情。
          當(dāng)我們啟動(dòng)一個(gè)應(yīng)用,計(jì)算機(jī)會(huì)創(chuàng)建一個(gè)進(jìn)程,操作系統(tǒng)會(huì)為進(jìn)程分配一部分內(nèi)存,應(yīng)用的所有狀態(tài)都會(huì)保存在這塊內(nèi)存中,應(yīng)用也許還會(huì)創(chuàng)建多個(gè)線程來輔助工作,這些線程可以共享這部分內(nèi)存中的數(shù)據(jù)。如果應(yīng)用關(guān)閉,進(jìn)程會(huì)被終結(jié),操作系統(tǒng)會(huì)釋放相關(guān)內(nèi)存。更生動(dòng)的示意圖如下:

          進(jìn)程(process)和線程(thread)
          一個(gè)進(jìn)程還可以要求操作系統(tǒng)生成另一個(gè)進(jìn)程來執(zhí)行不同的任務(wù),系統(tǒng)會(huì)為新的進(jìn)程分配獨(dú)立的內(nèi)存,兩個(gè)進(jìn)程之間可以使用 IPC (Inter Process Communication)進(jìn)行通信。很多應(yīng)用都會(huì)采用這樣的設(shè)計(jì),如果一個(gè)工作進(jìn)程反應(yīng)遲鈍,重啟這個(gè)進(jìn)程不會(huì)影響應(yīng)用其它進(jìn)程的工作。

          進(jìn)程間通過 IPC 通信
          如果對(duì)進(jìn)程及線程的理解還存在疑惑,可以參考下述文章。
          進(jìn)程與線程的一個(gè)簡單解釋 - 阮一峰的網(wǎng)絡(luò)日志:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
          瀏覽器的架構(gòu)
          有了上面的知識(shí)做鋪墊,我們可以更合理的討論瀏覽器的架構(gòu)了,其實(shí)如果要開發(fā)一個(gè)瀏覽器,它可以是單進(jìn)程多線程的應(yīng)用,也可以是使用 IPC 通信的多進(jìn)程應(yīng)用。
          不同瀏覽器的架構(gòu)模型
          不同瀏覽器采用了不同的架構(gòu)模式,這里并不存在標(biāo)準(zhǔn),本文以 Chrome 為例進(jìn)行說明 :
          Chrome 采用多進(jìn)程架構(gòu),其頂層存在一個(gè) Browser process 用以協(xié)調(diào)瀏覽器的其它進(jìn)程。

          Chrome 的不同進(jìn)程
          具體說來,Chrome 的主要進(jìn)程及其職責(zé)如下:
          • Browser Process:

          1. 負(fù)責(zé)包括地址欄,書簽欄,前進(jìn)后退按鈕等部分的工作;

          2. 負(fù)責(zé)處理瀏覽器的一些不可見的底層操作,比如網(wǎng)絡(luò)請(qǐng)求和文件訪問;


          • Renderer Process:

          1. 負(fù)責(zé)一個(gè) tab 內(nèi)關(guān)于網(wǎng)頁呈現(xiàn)的所有事情


          • Plugin Process:

          1. 負(fù)責(zé)控制一個(gè)網(wǎng)頁用到的所有插件,如 flash


          • GPU Process

          1. 負(fù)責(zé)處理 GPU 相關(guān)的任務(wù)



          不同進(jìn)程負(fù)責(zé)的瀏覽器區(qū)域示意圖
          Chrome 還為我們提供了「任務(wù)管理器」,供我們方便的查看當(dāng)前瀏覽器中運(yùn)行的所有進(jìn)程及每個(gè)進(jìn)程占用的系統(tǒng)資源,右鍵單擊還可以查看更多類別信息。
          通過「頁面右上角的三個(gè)點(diǎn)點(diǎn)點(diǎn) —- 更多工具 —- 任務(wù)管理器」即可打開相關(guān)面板,

          Chrome 任務(wù)管理器面板
          Chrome 多進(jìn)程架構(gòu)的優(yōu)缺點(diǎn)
          優(yōu)點(diǎn)
          1. 某一渲染進(jìn)程出問題不會(huì)影響其他進(jìn)程

          2. 更為安全,在系統(tǒng)層面上限定了不同進(jìn)程的權(quán)限

          缺點(diǎn)
          由于不同進(jìn)程間的內(nèi)存不共享,不同進(jìn)程的內(nèi)存常常需要包含相同的內(nèi)容。
          為了節(jié)省內(nèi)存,Chrome 限制了最多的進(jìn)程數(shù),最大進(jìn)程數(shù)量由設(shè)備的內(nèi)存和 CPU 能力決定,當(dāng)達(dá)到這一限制時(shí),新打開的 Tab 會(huì)共用之前同一個(gè)站點(diǎn)的渲染進(jìn)程。
          Chrome 多進(jìn)程架構(gòu)的優(yōu)缺點(diǎn)
          測試了一下在 Chrome 中打開不斷打開知乎首頁,在 Mac i5 8g 上可以啟動(dòng)四十多個(gè)渲染進(jìn)程,之后新打開 tab 會(huì)合并到已有的渲染進(jìn)程中。
          Chrome 把瀏覽器不同程序的功能看做服務(wù),這些服務(wù)可以方便的分割為不同的進(jìn)程或者合并為一個(gè)進(jìn)程。以 Broswer Process 為例,如果 Chrome 運(yùn)行在強(qiáng)大的硬件上,它會(huì)分割不同的服務(wù)到不同的進(jìn)程,這樣 Chrome 整體的運(yùn)行會(huì)更加穩(wěn)定,但是如果 Chrome 運(yùn)行在資源貧瘠的設(shè)備上,這些服務(wù)又會(huì)合并到同一個(gè)進(jìn)程中運(yùn)行,這樣可以節(jié)省內(nèi)存,示意圖如下。
          不同性能的硬件的不同進(jìn)程劃分
          iframe 的渲染 — Site Isolation
          在上面的進(jìn)程圖中我們還可以看到一些進(jìn)程下還存在著 Subframe,這就是 Site Isolation 機(jī)制作用的結(jié)果。
          Site Isolation 機(jī)制從 Chrome 67 開始默認(rèn)啟用。這種機(jī)制允許在同一個(gè) Tab 下的跨站 iframe 使用單獨(dú)的進(jìn)程來渲染,這樣會(huì)更為安全。


          iframe 會(huì)采用不同的渲染進(jìn)程
          Site Isolation 被大家看做里程碑式的功能, 其成功實(shí)現(xiàn)是多年工程努力的結(jié)果。Site Isolation 不是簡單的疊加多個(gè)進(jìn)程。這種機(jī)制在底層改變了 iframe 之間通信的方法,Chrome 的其它功能都需要做對(duì)應(yīng)的調(diào)整,比如說 devtools 需要相應(yīng)的支持,甚至 Ctrl + F 也需要支持。關(guān)于 Site Isolation 的更多內(nèi)容可參考下述鏈接
          https://developers.google.com/web/updates/2018/07/site-isolationdevelopers.google.com
          介紹完了瀏覽器的基本架構(gòu)模式,接下來我們看看一個(gè)常見的導(dǎo)航過程對(duì)瀏覽器來說究竟發(fā)生了什么。

          導(dǎo)航過程發(fā)生了什么

          也許大多數(shù)人使用 Chrome 最多的場景就是在地址欄輸入關(guān)鍵字進(jìn)行搜索或者輸入地址導(dǎo)航到某個(gè)網(wǎng)站,我們來看看瀏覽器是怎么看待這個(gè)過程的。
          我們知道瀏覽器 Tab 外的工作主要由 Browser Process 掌控,Browser Process 又對(duì)這些工作進(jìn)一步劃分,使用不同線程進(jìn)行處理:
          • UI thread :控制瀏覽器上的按鈕及輸入框;

          • network thread: 處理網(wǎng)絡(luò)請(qǐng)求,從網(wǎng)上獲取數(shù)據(jù);

          • storage thread: 控制文件等的訪問;

          瀏覽器主進(jìn)程中的不同線程
          回到我們的問題,當(dāng)我們?cè)跒g覽器地址欄中輸入文字,并點(diǎn)擊回車獲得頁面內(nèi)容的過程在瀏覽器看來可以分為以下幾步:
          處理輸入
          UI thread 需要判斷用戶輸入的是 URL 還是 query;
          開始導(dǎo)航
          當(dāng)用戶點(diǎn)擊回車鍵,UI thread 通知 network thread 獲取網(wǎng)頁內(nèi)容,并控制 tab 上的 spinner 展現(xiàn),表示正在加載中。
          network thread 會(huì)執(zhí)行 DNS 查詢,隨后為請(qǐng)求建立 TLS 連接


          UI thread 通知 Network thread 加載相關(guān)信息
          如果 network thread 接收到了重定向請(qǐng)求頭如 301,network thread 會(huì)通知 UI thread 服務(wù)器要求重定向,之后,另外一個(gè) URL 請(qǐng)求會(huì)被觸發(fā)。
          讀取響應(yīng)
          當(dāng)請(qǐng)求響應(yīng)返回的時(shí)候,network thread 會(huì)依據(jù)?Content-Type?及 MIME Type sniffing 判斷響應(yīng)內(nèi)容的格式

          判斷響應(yīng)內(nèi)容的格式
          如果響應(yīng)內(nèi)容的格式是 HTML ,下一步將會(huì)把這些數(shù)據(jù)傳遞給 renderer process,如果是 zip 文件或者其它文件,會(huì)把相關(guān)數(shù)據(jù)傳輸給下載管理器。
          Safe Browsing 檢查也會(huì)在此時(shí)觸發(fā),如果域名或者請(qǐng)求內(nèi)容匹配到已知的惡意站點(diǎn),network thread 會(huì)展示一個(gè)警告頁。此外 CORB 檢測也會(huì)觸發(fā)確保敏感數(shù)據(jù)不會(huì)被傳遞給渲染進(jìn)程。
          查找渲染進(jìn)程


          當(dāng)上述所有檢查完成,network thread 確信瀏覽器可以導(dǎo)航到請(qǐng)求網(wǎng)頁,network thread 會(huì)通知 UI thread 數(shù)據(jù)已經(jīng)準(zhǔn)備好,UI thread 會(huì)查找到一個(gè) renderer process 進(jìn)行網(wǎng)頁的渲染。
          收到 Network thread 返回的數(shù)據(jù)后,UI thread 查找相關(guān)的渲染進(jìn)程


          由于網(wǎng)絡(luò)請(qǐng)求獲取響應(yīng)需要時(shí)間,這里其實(shí)還存在著一個(gè)加速方案。當(dāng) UI thread 發(fā)送 URL 請(qǐng)求給 network thread 時(shí),瀏覽器其實(shí)已經(jīng)知道了將要導(dǎo)航到那個(gè)站點(diǎn)。UI thread 會(huì)并行的預(yù)先查找和啟動(dòng)一個(gè)渲染進(jìn)程,如果一切正常,當(dāng) network thread 接收到數(shù)據(jù)時(shí),渲染進(jìn)程已經(jīng)準(zhǔn)備就緒了,但是如果遇到重定向,準(zhǔn)備好的渲染進(jìn)程也許就不可用了,這時(shí)候就需要重啟一個(gè)新的渲染進(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)程包含的線程
          1. 主線程 Main thread

          2. 工作線程 Worker thread

          3. 排版線程 Compositor thread

          4. 光柵線程 Raster thread

          后文我們將逐步介紹不同線程的職責(zé),在此之前我們先看看渲染的流程
          1. 構(gòu)建 DOM

          當(dāng)渲染進(jìn)程接收到導(dǎo)航的確認(rèn)信息,開始接受 HTML 數(shù)據(jù)時(shí),主線程會(huì)解析文本字符串為 DOM。
          渲染 html 為 DOM 的方法由 HTML Standard 定義。
          1. 加載次級(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)資源的下載。
          1. JS 的下載與執(zhí)行

          當(dāng)遇到?
          <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>
                    亚洲性爱电影院 | www.黄色在线观看 | 亚洲AV成人无码精在线 | igao视频在线观看 | 国产欧美日韩视频 |