Life of a Pixel 原本是 Chromium 團隊在入職培訓時的培訓資料,其目的是爲了讓新入職的同事可以從大致上快速的瞭解 Chromium 的架構,而不是糾結於代碼邏輯。如今該團隊正式將其發佈,也是爲了對於此感興趣的工程師可以快速的瞭解項目,參與項目的開發協做。本視頻的內容,從宏觀上來講,就是本演講的題目 Life of a Pixel,直譯就是一個像素點的一輩子,表示該演講做者但願觀衆可以在視頻結束後瞭解,前端的工程師所完成的代碼,是如何經過瀏覽器,變爲一個又一個的像素點,以及像素點是如何更新和毀滅的。前端
web content (代碼) ➡️ magic (渲染) ➡️pixels (像素)python
瀏覽器真正渲染的內容在紅框內,以外的都是非渲染的部分。渲染的引擎能夠看作是一個黑箱,在 Chromium 中,咱們把它稱爲 Blink。git
同時,在渲染時,咱們須要調用圖像處理的底層 API 去進行渲染,對於此,有官方的統一標準就是 openGL,可是,對於 Windows,可能還須要轉化爲 DirectX。對於此,團隊正在開發一個新項目名爲 Vulkan,爲了進行統一化。固然,這種底層的 API 並不能讀懂咱們的 HTML 和 CSS,它們只能作一些簡單得圖像繪製,諸如畫一些多邊形這種操做。web
因此,咱們再梳理一遍流程。總的來講就是咱們要將 web content 轉化爲對於的圖像處理的 API,在電腦屏幕上進行繪製。在這個過程當中,爲了更好地將已經渲染的圖像更新,咱們要設計一種數據結構,可以幫助咱們更新這個頁面的結構與內容和頁面樣式。這些更新就包括咱們熟知的 JavaScript API,用戶在輸入框輸入,異步加載,動畫,卷軸移動,頁面縮放。後端
HTML 的結構,是一種自然的語義化的繼承式的結構。語義化是標籤所帶來的,集成式是樹狀結構所帶來的。咱們能夠將 HTML 看作輸入進行解析,成爲一顆咱們熟知的 DOM 樹。很好的詮釋了父子間,兄弟間的關係。咱們也能夠很直觀的從 JavaScript 所暴露出的 DOM API 中發現。瀏覽器
在 CSS 解析時,解析器會將每個選擇器所選擇的 CSS 屬性名和屬性值保存,做爲 map,同時視頻中說起,CSS 屬性名是由 C++ 進行生成的,該 C++ 文件在構建時由 python 腳本自動生成。下一步,稱爲重計算(recalc),對於全部產生的屬性,咱們會計算它們的疊加和,做爲每個 DOM 元素的每個屬性的值,這個值咱們也稱爲計算值。也就是最終渲染的結構。這個屬性值咱們可使用 Chrome 的 API 或者是 JavaScript DOM API 都可以獲得。數據結構
基於 Layout Tree,咱們就能夠處理 overflow 等一系列複雜狀況。但還有一個個問題是,這種數據結構沒有將輸入的計算屬性和輸出的視圖位置分離開,因此這裏說起了一個正在開發的新項目名爲 LayoutNG 就是爲了解決這個問題。架構
咱們假設初次渲染已經完成,可是,對於前端的快速發展,大量的邏輯已經由後端轉往前端實現,DOM 的更新變得異常頻繁。簡單地說,咱們須要在原有 DOM 上作適量的改動從新渲染。爲了避免從新將上圖的整個流程所有再次進行,這裏咱們就須要將其中的某些狀態保留,提升更新效率。異步
在更新渲染時,有時咱們會縮放頁面,區域滾動,或者是有動畫。在這類型的狀況下,若是渲染速率低於60幀,那麼人眼看到會變得有些卡頓。佈局
因此咱們要儘量判斷出在上節提到的每個步驟中,有哪些元素是須要改變的,哪些不須要是能夠從新利用的,作到效率的優化。這也是在技術實現中也被考慮到的地方。
可是,實際狀況是,有時一個大的區域所有改變,那麼咱們不得不對這個大的區域進行所有從新渲染,好比區域滾動。
還要注意的是 JavaScript 的設計是單線程的,也就意味着在渲染時,加入有 JS 腳本的執行,就會阻塞當前的渲染。
基於以前提到的種種問題,Chromium 團隊提出了 compositing 這種解決方案。目的就是優化性能。有點相似於 Photoshop,簡單得說,有兩點:
在咱們進行動畫,滾動,縮放等操做時,瀏覽器會監聽用戶的輸入行爲,在 impl 線程上進行工做,使得主線程執行 JavaScript,互不干擾,可是假如 impl 線程發現這個事件沒法處理,則仍是會交還給主線程。
在實現層這個概念時仍是會借鑑初次渲染的數據結構,也就是樹,稱爲 Layer Tree。它是命名在 cc(Chromium compositor)下,主要數據信息由以前的 Layout Tree 繼承而來。注意,這裏還有一個 PaintLayer Tree, 相似於一箇中間狀態,將一個 Layout Object 進行分層,而且賦予其功能,例如對子元素進行裁切或者是施加別的效果。
天然而然,咱們將會在 layout 和 paint 這兩個階段中加入 compositing update 去加快大區域從新渲染,得到 layer tree。須要注意的是,如今團隊中正在進行一個工程,稱爲 slimming paint,將 layer tree 的創建放在 paint 階段後,目的是爲了將每一層 layer 的創建變得更加獨立,而且創建屬性樹,提取出獨立或者公共的屬性,儘量地將其放到真正像素級渲染以前。當 impl 線程的 paint 階段結束後,就能夠通知主線程進行同步,有點相似於使用 git 在不一樣分支上合併代碼。
在 raster 以前還有一步優化,對於大面積滾動視圖,沒有必要一開始將全部的內容所有變換成 bitmaps,咱們只須要將視窗中的先進行轉化,在這裏有一個 tiling manager,它負責將區域分塊,就像地板上的瓦塊同樣,隨着滾動區域的變化,將相鄰區域的瓦塊優先渲染。
全部主要的階段已經大致介紹完畢。歡迎補充和加深!
感謝張冀韜同窗將演講內容梳理成文章並於掘金首發。