瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結

梳理瀏覽器襯着流程

起首簡樸相識一下瀏覽器要求、加載、襯着一個頁面的大抵歷程:

  • DNS 查詢
  • TCP 銜接
  • HTTP 要求即相應
  • 服務器相應
  • 客戶端襯着

這裏主要將客戶端襯着睜開梳理一下,從瀏覽器器內核拿到內容(襯着線程吸收要求,加載網頁並襯着網頁),襯着也許能夠劃分紅以下幾個步驟:

  • 剖析html豎立dom樹
  • 剖析css構建render樹(將CSS代碼剖析成樹形的數據結構,然後連繫DOM兼并成render樹)
  • 規劃render樹(Layout/reflow),擔任各元素尺寸、位置的盤算
  • 繪製render樹(paint),繪製頁面像素信息
  • 瀏覽器會將各層的信息發送給GPU(GPU歷程:最多一個,用於3D繪製等),GPU會將各層合成(composite),顯如今屏幕上。

參考一張圖(webkit襯着主要流程):

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

這裏先解釋一下幾個觀點,輕易人人明白:

  DOM Tree:瀏覽器將HTML剖析成樹形的數據結構。

  CSS Rule Tree:瀏覽器將CSS剖析成樹形的數據結構。

  Render Tree: DOM和CSSOM兼并後天生Render Tree。

  layout: 有了Render Tree,瀏覽器已能曉得網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關係,從而去盤算出每一個節點在屏幕中的位置。

  painting: 根據算出來的劃定規矩,經由過程顯卡,把內容畫到屏幕上。

  reflow(迴流):當瀏覽器發明某個部份發作了點變化影響了規劃,須要倒回去從新襯着,行家稱這個回退的歷程叫 reflow。reflow 會從 <html> 這個 root frame 最先遞歸往下,順次盤算一切的結點多少尺寸和位置。reflow 幾乎是沒法防止的。如今界面上盛行的一些結果,比方樹狀目次的摺疊、睜開(實質上是元素的顯 示與隱蔽)等,都將激發瀏覽器的 reflow。鼠標滑過、點擊……只需這些行動激發了頁面上某些元素的佔位面積、定位體式格局、邊距等屬性的變化,都邑激發它內部、四周以至全部頁面的從新渲 染。平常我們都沒法預估瀏覽器到底會 reflow 哪一部份的代碼,它們都相互相互影響着。

  repaint(重繪):轉變某個元素的背景色、筆墨色彩、邊框色彩等等不影響它四周或內部規劃的屬性時,屏幕的一部份要重畫,然則元素的多少尺寸沒有變。

注重:

  1. display:none 的節點不會被到場Render Tree,而visibility: hidden
    則會,所以,假如某個節點最最先是不顯現的,設為display:none是更優的。
  2. display:none 會觸發 reflow,而 visibility:hidden 只會觸發 repaint,因為沒有發明位置變化。
  3. 有些狀況下,比方修改了元素的款式,瀏覽器並不會立時reflow 或 repaint 一次,而是會把如許的操縱積累一批,然後做一次reflow,這又叫異步 reflow 或增量異步 reflow。然則在有些狀況下,比方resize窗口,轉變了頁面默許的字體等。關於這些操縱,瀏覽器會立時舉行 reflow。

再參考一張圖明白一下:

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

細緻星散兩個環節,其他環節參考上述觀點註解:

JavaScript:JavaScript完成動畫結果,DOM元素操縱等。
Composite(襯着層兼并):對頁面中 DOM 元素的繪製是在多個層上舉行的。在每一個層上完成繪製歷程以後,瀏覽器會將一切層根據合理的遞次兼并成一個圖層,然後顯如今屏幕上。關於有位置堆疊的元素的頁面,這個歷程特別主要,因為一旦圖層的兼并遞次失足,將會致使元素顯現異常。

在現實場景下,大抵會湧現三種罕見的襯着流程(Layout和Paint步驟是可防止的,可參考上一張圖的注重部份明白):

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

Composite

相識層

注重:起首申明,這裏議論的是 WebKit,形貌的是 Chrome 的完成細節,而並非是 web 平台的功用,因而這裏引見的內容不一定適用於其他瀏覽器。

  • Chrome 具有兩套差別的襯着途徑(rendering path):硬件加快途徑和舊軟件途徑(older software path)
  • Chrome 中有差別範例的層: RenderLayer(擔任 DOM 子樹)和GraphicsLayer(擔任 RenderLayer的子樹),只要 GraphicsLayer 是作為紋理(texture)上傳給GPU的。
  • 什麼是紋理?能夠把它設想成一個從主存儲器(比方 RAM)挪動到圖象存儲器(比方 GPU 中的 VRAM)的位圖圖象(bitmapimage)
  • Chrome 運用紋理來從 GPU上取得大塊的頁面內容。經由過程將紋理運用到一個異常簡樸的矩形網格就可以很輕易婚配差別的位置(position)和變形(transformation)。這也就是3DCSS 的事情道理,它關於疾速轉動也非常有用。

全部圖:

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

在 Chrome 中其實有幾種差別的層範例:

  • RenderLayers 襯着層,這是擔任對應 DOM 子樹
  • GraphicsLayers 圖形層,這是擔任對應 RenderLayers子樹。

在瀏覽器襯着流程中提到了composite觀點,在 DOM 樹中每一個節點都邑對應一個 LayoutObject,當他們的 LayoutObject 處於雷同的坐標空間時,就會構成一個 RenderLayers ,也就是襯着層。RenderLayers 來保證頁面元素以準確的遞次合成,這時刻就會湧現層合成(composite),從而準確處置懲罰通明元素和堆疊元素的顯現。

某些特別的襯着層會被認為是合成層(Compositing Layers),合成層具有零丁的 GraphicsLayer,而其他不是合成層的襯着層,則和其第一個具有 GraphicsLayer 父層公用一個。

而每一個GraphicsLayer(合成層零丁具有的圖層) 都有一個 GraphicsContext,GraphicsContext 會擔任輸出該層的位圖,位圖是存儲在同享內存中,作為紋理上傳到 GPU 中,末了由 GPU 將多個位圖舉行合成,然後顯現到屏幕上。

怎樣變成合成層

合成層建立規範

什麼狀況下能使元素取得自身的層?雖然 Chrome的啟髮式要領(heuristic)跟着時刻在不斷髮展提高,然則從現在來講,滿足以下恣意狀況便會建立層:

  • 3D 或透視變更(perspective transform) CSS 屬性
  • 運用加快視頻解碼的 <video> 元素 具有 3D
  • (WebGL) 上下文或加快的 2D 上下文的 <canvas> 元素
  • 夾雜插件(如 Flash)
  • 對自身的 opacity 做 CSS動畫或運用一個動畫變更的元素
  • 具有加快 CSS 過濾器的元素
  • 元素有一個包含複合層的子女節點(換句話說,就是一個元素具有一個子元素,該子元素在自身的層里)
  • 元素有一個z-index較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上面襯着)

合成層的長處

淘寶的栗子舉的很細緻,值得一看,內里提到了一旦renderLayer提拔為了合成層就會有自身的畫圖上下文,並且會開啟硬件加快,有利於機能提拔,內里列舉了一些特性

  • 合成層的位圖,會交由 GPU 合成,比 CPU 處置懲罰要快
  • 當須要 repaint 時,只須要 repaint 自身,不會影響到其他的層
  • 關於 transform 和 opacity 結果,不會觸發 layout 和 paint

注重:

  1. 提拔到合成層后合成層的位圖會交GPU處置懲罰,但請注重,僅僅只是合成的處置懲罰(把畫圖上下文的位圖輸出舉行組合)須要用到GPU,天生合成層的位圖處置懲罰(畫圖上下文的事情)是須要CPU。
  2. 當須要repaint的時刻能夠只repaint自身,不影響其他層,然則paint之前另有style, layout,那就意味着縱然合成層只是repaint了自身,但style和layout自身就很佔用時刻。
  3. 僅僅是transform和opacity不會激發layout 和paint,那末其他的屬性不確定。

總連繫成層的上風:平常一個元素開啟硬件加快後會變成合成層,能夠自力於一般文檔流中,修改后能夠防止全部頁面重繪,提拔機能。

機能優化點:

  1. 提拔動畫結果的元素 合成層的優點是不會影響到其他元素的繪製,因而,為了削減動畫元素對其他元素的影響,從而削減paint,我們須要把動畫結果中的元素提拔為合成層。 提拔合成層的最好體式格局是運用 CSS 的 will-change屬性。從上一節合成層發生緣由中,能夠曉得 will-change 設置為opacity、transform、top、left、bottom、right 能夠將元素提拔為合成層。
  2. 運用 transform 或許 opacity 來完成動畫結果, 如許只須要做合成層的兼并就好了。
  3. 削減繪製地區 關於不須要從新繪製的地區應只管防止繪製,以削減繪製地區,比方一個 fix 在頁面頂部的牢固穩定的導航header,在頁面內容某個地區 repaint 時,全部屏幕包含 fix 的 header 也會被重繪。而關於牢固穩定的地區,我們希冀其並不會被重繪,因而能夠經由過程之前的要領,將其提拔為自力的合成層。削減繪製地區,須要細緻分析頁面,辨別繪製地區,削減重繪地區以至防止重繪。

運用合成層能夠踩到的坑

  1. 合成層佔用內存的題目
  2. 層爆炸,因為某些緣由能夠致使發生大批不在預期內的合成層,雖然有瀏覽器的層緊縮機制,然則也有許多沒法舉行緊縮的狀況,這就能夠湧現層爆炸的徵象(簡樸明白就是,許多不須要提拔為合成層的元素因為某些不當操縱成為了合成層)。處理層爆炸的題目,最好計劃是突破 overlap 的前提,也就是說讓其他元素不要和合成層元素堆疊。簡樸直接的體式格局:運用3D硬件加快提拔動畫機能時,最好給元素增添一個z-index屬性,工資滋擾合成的排序,能夠有用削減chrome建立不必要的合成層,提拔襯着機能,挪動端優化結果尤其顯著。 在這篇文章中的demo能夠看出个中兇猛。

用chremo翻開demo頁面后,開啟瀏覽器的開闢者形式,再根據如圖操縱翻開檢察東西:

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

開啟 Rendering 的Layer borders后 視察點擊為動畫元素設置z-index複選框的頁面提醒變化:

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

上圖中能夠顯著看出:頁面中設置了一個h1題目,運用了translate3d動畫,使得它被放到composited layer中襯着,然後在這個元素背面建立了2000個list。在不為h1元素設置z-index的狀況下,使得本不須要提拔到合成層的ul元素下的每一個li元素都提拔為一個零丁合成層(每一個li元素的黃色提醒邊框),最終會致使GPU資本過分斲喪頁面滑動時很卡,特別在挪動端(安卓)上越發顯著。

《瀏覽器襯着流程&Composite(襯着層兼并)簡樸總結》

如上圖操縱選中為動畫元素設置z-index,能夠看出ul下的每一個li都回歸到一般襯着層,不再是合成層也就不會斲喪GPU資本去襯着,從而到達了優化頁面機能優化的目標。

人人能夠用支撐『硬件加快』的『安卓』手機瀏覽器測試上述頁面,給動畫元素加z-index前後的機能差異異常顯著。

末了

在現實的前端開闢中特別是挪動端開闢,許多小夥伴都很喜好運用相似 translateZ(0)等屬性來舉行所謂的硬件加快,以提拔機能,到達優化頁面動態結果的目標,但照樣要注重凡事矯枉過正,運用硬件加快的同時也要注重到千萬別踩坑。
關於合成層的更細緻詳細的解說,能夠細緻進修下下面的參考文章(特別是前三篇哦)。
末了祝賀酷愛手藝的你我一直對峙在探究手藝的路上奮力前行!

參考文章:
無線機能優化:Composite
DOM to Screen
CSS GPU Animation: Doing It Right
web優化之composite
詳談層合成(composite)
CSS3硬件加快也有坑

    原文作者:海麗安娜
    原文地址: https://segmentfault.com/a/1190000014520786
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞