CPU:Central Processing Unit(中央處理器),中心處理器是計算機的大腦,每一個CPU核心會逐一執行不一樣任務如今不少計算機都是多芯片,多內核的。css
GPU:Graphics Processing Unit(圖形處理器),GPU擅長處理跨內核的簡單任務,是爲了解決圖形而開發的。在圖形環境中,「使用GPU支持」和「使用CPU」都與快速渲染與順滑渲染有關。html
當啓動電腦時候,是CPU和GPU爲應用供能。一般狀況下,應用是經過操做系統提供的機制在CPU和GPU上運行。html5
進程能夠被描述爲一個應用的執行程序,線程存在於進程並執行任意部分。web
啓動應用時,會建立一個或者多個進程來幫助應用工做,操做系統爲進程提供了一塊可使用的「內存」,應用的全部狀態都保存在該私有內存空間中,關閉應用,進程會關閉,操做系統釋放內存。跨域
進程能夠請求操做系統的另外一個進程來執行不一樣的任務。此時,會分配不一樣的內存給新進程,進程之間能夠經過(IPC:Inter Process Communication)進行通信。應用的某個工做進程失去響應,該進程就能夠在不中止應用程序其餘進程的狀況下,重啓。瀏覽器
不一樣的瀏覽器多是多進程或者單進程的。緩存
Chrome瀏覽器架構,使用多進程的架構安全
瀏覽器頂層是瀏覽器進程(Browser process),與瀏覽器其餘應用模塊進行協調工做。 bash
Chrome瀏覽器各個進程的工做:服務器
谷歌瀏覽器每個站點(網頁)都是獨立的進程,這樣能夠保證即便網頁崩潰了,其餘網頁也不會受到影響。瀏覽器有多個進程的好處就是安全性跟跟沙箱化。因爲操做系統提供了限制進程權限的方法,瀏覽器就能夠用沙箱保護某些進程。因爲進程有本身的私有內存空間,因此每一個進程都有公共基礎設施的拷貝,這也意味着會佔用更多的內存,當運行達到極限時候,Chrome對於同一站點的不一樣標籤頁,會使用同一進程。
當Chrome運行在強力硬件上時,會把不一樣的服務功能模塊分配到不一樣的進程,從而提高穩定性,可是當運行在弱硬件設備時候,會將一些服務功能模塊整合到同一個進程以節約內存,可是相應的穩定性也會降低。
站點隔離實現每一個Iframe運行在獨立的渲染進程。每一個tab站點單獨運行一個進程,站點內的Iframe運行一個單獨的渲染進程,這樣在不一樣的站點內,相同Iframe能夠共享內存。
同源策略是web的安全模型,也就是某一站點在沒有受權的狀況下,其餘站點是不能獲取其數據的。進程隔離是分離站點的最高效手段。
它以瀏覽器進程(Browser Process)開始
瀏覽器進程管理一切除Ta外以外的一切,瀏覽器進程內有不少線程,例如繪製瀏覽器的按鈕和輸入欄的UI線程、處理網絡棧以從因特網獲取獲取的網絡線程、控制文件訪問的存儲線程。當輸入URL,輸入由瀏覽器的進程的UI線程處理。
瀏覽器進程的UI線程首先肯定是搜索查詢仍是一個URL。UI線程決定是搜索內容到搜索引擎仍是去一個網站。
SSL(Secure Sockets Layer 安全套接層),及其繼任者傳輸層安全(Transport Layer Security,TLS)是爲網絡通訊提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網絡鏈接進行加密。
SSL協議位於TCP/IP協議與各類應用層協議之間,爲數據通信提供安全支持。SSL協議可分爲兩層: SSL記錄協議(SSL Record Protocol):它創建在可靠的傳輸協議(如TCP)之上,爲高層協議提供數據封裝、壓縮、加密等基本功能的支持。
安全傳輸層協議(TLS)用於在兩個通訊應用程序之間提供保密性和數據完整性。該協議由兩層組成: TLS 記錄協議(TLS Record)和 TLS 握手協議(TLS Handshake)。較低的層爲 TLS 記錄協議,位於某個可靠的傳輸協議(例如 TCP)上面,與具體的應用無關,因此,通常把TLS協議歸爲傳輸層安全協議。
在這時,網絡線程可能會收到像 HTTP 301 那樣的服務器重定向頭。這種狀況下,網絡線程會告訴 UI 線程,服務器正在請求重定向。而後,另外一個 URL 請求會被啓動。
一旦開始收到響應主體,網絡線程會查看數據流的前幾個字節,響應報文的Content-Type字段會聲明數據的類型。但可能存在丟失會錯誤。因此有了MIME類型嗅探來解決這個問題。
若是響應是一個HTML文件,那麼下一步就會把數據傳給渲染進程,若是是一個下載的文件,意味着是一個下載請求,會把它傳遞給下載器管理器。
此時也會進行safeBrowsing檢查,若是域名和數據匹配到一個惡意網站,那麼網絡線程會顯示一個警告頁面。此外也會進行Cross Origin Read Bloking (CORB)檢查,以確保敏感的跨域數據不被傳給渲染進程。
一旦全部的檢查處理完畢而且網絡線程肯定會導航到請求的站點,網絡請求線程會告訴UI線程全部的數據請求完畢。UI線程會尋找渲染進程開始渲染Web頁面。
因爲網絡請求線程會花費時間,一次能夠應用一個優化措施,當UI線程正發送一個URL請求給網絡線程時候,能夠同時查找開啓一個渲染進程待命,若是導航重定向,這個渲染進程或許不會用到。
如今數據和渲染進程就緒,瀏覽器會發送一個IPC(進程間通訊)到渲染進程去提交導航,他也會傳遞數據流,因此渲染進程會保持接受HTML數據,一旦瀏覽器進程收到渲染進程已經提交的確認信息,導航完畢而且文檔加載解析開始。
這時,地址欄已經更新,安全指示器和站點設置UI會放映新頁面的站點信息,此標籤頁的session歷史記錄被更新,因此前進後退按鈕會走向剛導航過的站點, 當你關閉標籤頁或者窗口,爲了優化Tab/session的還原,session歷史被保存在硬盤上。
一旦導航別提交,渲染進程開始加載資源和渲染頁面,一旦渲染進程渲染完畢,會發送IPC返回給瀏覽器進程,(這也會全部frameh和onload事件已經觸發和執行完畢後發生)。這時,UI線程中止標籤頁上的加載動畫。
簡單導航已經完成,在導航欄在輸入一個URL時,瀏覽器進程會先檢查已經渲染的站點是否關心beforeUnload事件,確認沒有的話,就會執行相同的操做,導航到另外一個站點。
befounload事件會在用戶離開或者關閉標籤頁面時候給予提醒「離開此站點」。
若是渲染進程啓動了導航(window.location.herf=xxx),渲染進程會先檢查befoeload事件處理程序,會像瀏覽器處理導航同樣執行相同的步驟,惟一不一樣的是導航請求是由渲染進程發送到瀏覽器進程的。
當新導航到新站點時,會調用一個獨立的渲染進程來處理導航,同時保留當前的渲染進程來處理unload事件。
渲染進程負責標籤內發送的全部事情。渲染進程中,主線程處理服務器返回給用戶的大部分數據,若是使用了web sworker或Service Sorker,部分JS將由工做線程處理。合成和光柵線程也在渲染進程內運行,以高效流暢的呈現頁面。
渲染進程的核心工做是將HTML,CSS和JavaScript轉換爲用戶能夠與之交互的網頁。
HTML的標籤的解析由HTML Standar決定,HTML規範能夠很優雅的處理一些標籤錯誤。
網站的圖像,CSS,JS外部資源,須要從網路或者緩存加載。解析構建DOM時,主線程會按處理順序逐個加載,爲了加快速度,「預加載掃描器(preload scanner)」會同時進行。若是文檔有<img><link>
,預加載掃描器會在瀏覽器進程中發送請求。
3.JS阻塞解析 當解析HTML時,遇到<script>
時,會中止解析接下來的內容,加載js,並執行裏面的代碼。
能夠在<script>
標籤加async或者defer屬性,實現異步加載JS,或者加載JS模塊,可使用 <link rel="preload">
告知瀏覽器當前導航確定須要該資源,而且你但願儘快下載。
只有DOM元素沒法肯定頁面的外觀,須要結合CSS樣式。主線程解析CSS而且肯定每一個DOM節點計算後的樣式。
知道每一個節點已經對應的元素樣式,不足以渲染頁面。佈局是計算幾何元素形狀的過程,主線程遍歷DOM,計算樣式並建立佈局樹,其中包含xy座標和邊框大小等信息,佈局樹可能與DOM樹結構樹相似,但它僅包含頁面可見內容的信息。若是一個元素應用了 display:none,那麼該元素不是佈局樹的一部分。相似地,若是應用瞭如 p::before{content:"Hi!"} 的僞類,則即便它不在 DOM 中,也包含於佈局樹中。
有了DOM、樣式、佈局樹還不能畫出頁面,還不知道繪製的順序。 例如,有的元素有了z-index,簡單從上到下繪製就會出現圖層高低錯誤。
在繪製步驟,主線程遍歷佈局樹(Layout Tree)建立繪製記錄(Paint Records),就像是背景優先,而後矩形,文字。
渲染管道最重要的事情:每一個步驟,都是前一個操做的結果用於後一個操做的數據。若是爲元素設置動畫,每一幀都要進行相同的處理操做,大多數瀏覽器的1幀/秒 若是瀏覽器丟失了中間部分幀,就會讓人以爲卡頓。
如今知道了文檔的結構,CSS,佈局樹,繪製順序。就是將數據轉化爲物理設備上的像素了。這個過程成爲光柵化。
合成處理是將頁面的各個部分光柵化,而且合成線程進行圖層移動合成。
爲了分清哪些元素位於什麼圖層,主線程遍歷佈局樹建立圖層樹,若是某些部分是單獨圖層(例如劃入式側面菜單欄),但沒有拆分出來,能夠用CSS屬性:will-change提示瀏覽器。
一旦建立了圖層樹和肯定了繪製順序,主線程將會把信息傳遞給合成線程,接着,合成線程會光柵化每一個圖層,一個圖層可能跟頁面同樣大,合成線程將其分塊後發送給光柵線程。光柵線程光柵化每一個小塊後將他們存儲在顯存中。
合成線程會不一樣的光柵化線程設置優先級,以便視圖或者附近區域的畫面能夠先光柵化顯示。圖層還具備不一樣的分辨率的塊,能夠放大顯示。
一旦塊被光柵化,合成線程會收集這些塊的信息(稱爲繪製四邊形),建立合成幀。
接着,合成幀經過IPC提交給瀏覽器進程,此時,能夠在UI線程或者其餘插件的渲染進程添加一個合成幀,這些合成器幀被送到GPU而後在屏幕上顯示。若是收到滾動事件,合成幀會建立另外一個合成幀到GPU。
用戶的任何行爲,對於瀏覽器來講都是輸入行爲。包括點擊,滾動,觸摸屏幕,滑動鼠標。
例如用戶觸摸屏幕時,瀏覽器進程率先捕捉行爲,瀏覽器進程所掌握的信息僅限於行爲發生的區域,由於標籤內的內容都由渲染進程處理。瀏覽器進程會將點擊行爲以及座標傳達給渲染進程。渲染進程在進行相應的處理。
運行JS是渲染進程的主線程的工做,頁面合成以後,註冊了事件的區域叫作「非當即可滾動區」,合成器線程會通知渲染進程的主線程處理。沒有輸入事件沒有發生在事件註冊區域,合成器進程則不須要等待主線程,能夠繼續合成幀。
document.body.addEventListener('touchstart',
event => {
if (event.target === area) {
event.preventDefault();
}
});
複製代碼
事件代理是瀏覽器經常使用的事件處理模式,在頂層元素添加一個事件。 這樣帶來的問題就是整個頁面都被標識爲非當即滾動區域,合成器進程須要每次都詢問主線程是否須要處理事件而且等待反饋。流暢的合成器處理模式就失效了。
你能夠給事件監聽添加一個 passive:true 選項 ,將這種負面效果最小化。這會提示瀏覽器你想繼續在主線程中監聽事件,但合成器沒必要停滯等候,可接着建立新的合成幀。
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault()
}
}, {passive: true});
複製代碼
不過上述寫法可能又會帶來另一個問題,假設某個區域你只想要水平滾動,使用 passive: true
能夠實現平滑滾動,可是垂直方向的滾動可能會先於event.preventDefault()
發生,此時能夠經過 event.cancelable
來防止這種狀況。
document.body.addEventListener('pointermove', event => {
if (event.cancelable) {
event.preventDefault(); // 阻止默認的滾動行爲
/*
* 這裏設置程序執行任務
*/
}
}, {passive:: true});
複製代碼
也可使用css屬性 touch-action
來徹底消除事件處理器的影響,如:#area{touch-action:pan-x;}
當組合器線程發送輸入事件給主線程時,主線程首先會進行命中測試(hit test),來查找對應的時間目標,命中測試會基於渲染過程當中生成的繪製記錄(paint records)查找事件發生座標下尋找的元素。
#####事件的優化
通常咱們屏幕的刷新速率爲 60fps,可是某些事件的觸發量會不止這個值,出於優化的目的,Chrome 會合並連續的事件(如 wheel, mousewheel, mousemove, pointermove, touchmove ),並延遲到下一幀渲染時候執行 。而如 keydown, keyup, mouseup, mousedown, touchstart, 和 touchend 等非連續性事件則會當即被觸發。
事件合併可幫助大多數 web 應用構建良好的用戶體驗。然而,若是你開發的是一個繪圖類應用,須要基於 touchmove 事件的座標繪製線路,那麼在你試圖畫下一根光滑的線條時,區間內的一些座標點也可能會因事件合併而丟失。這時,你可使用目標事件的 getCoalescedEvents 方法獲取事件合併後的信息。
window.addEventListener('pointermove', event => {
const events = event.getCoalescedEvents();
for (let event of events) {
const x = event.pageX;
const y = event.pageY;
// 使用 x、y 座標畫線
}
});
複製代碼
參考: