天天看點

前端必備的浏覽器知識(渲染過程、回流和重繪等)

常用哪幾種浏覽器測試?有哪些浏覽器核心(Rendering Engine)?

(Q1)浏覽器:Chrome,IE,FireFox,Safari,Opera。

(Q2)對應核心:Webkit,Trident,Gecko,Webkit,Presto。(國内的浏覽器,除了傲遊是直接基于Webkit開發的,其他基本都是基于谷歌在webkit上開發的Chromium,當然谷歌自己也是用的Chromium。另外值得的一提的是手機的系統(安卓、蘋果)預設浏覽器都是基于webkit核心的)

如何了解浏覽器核心?

主要分成兩部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。後來JS引擎越來越獨立(比如谷歌的V8引擎),核心就傾向于隻指渲染引擎。

渲染引擎:負責取得網頁的内容(HTML、XML、圖像等等)、整理訊息(例如加入CSS等),以及計算網頁的顯示方式,然後會輸出至顯示器或列印機。浏覽器的核心的不同對于網頁的文法解釋會有不同,是以渲染的效果也不相同。所有網頁浏覽器、電子郵件用戶端以及其它需要編輯、顯示網絡内容的應用程式都需要核心。

JS引擎:解析和執行javascript來實作網頁的動态效果。

浏覽器的渲染過程?

當浏覽器獲得一個html檔案時,會“自上而下”加載,并在加載過程中進行解析渲染。

解析:

a. 浏覽器會将HTML解析成一個DOM樹,DOM 樹的建構過程是一個深度周遊過程:目前節點的所有子節點都建構好後才會去建構目前節點的下一個兄弟節點。

b. 将CSS解析成 CSS規則樹(Style Rule) 。

c. 根據DOM樹和CSS規則樹來構造 Rendering Tree(渲染樹)。注意:Rendering Tree并不等同于 DOM 樹,因為一些像 Header 或 display:none 的東西就沒必要放在渲染樹中了。

d. 有了Render Tree,浏覽器已經能知道網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關系。下一步操作稱之為Layout(布局),就是計算出每個節點在螢幕中的坐标。

e. 再下一步就是繪制,即周遊render樹,并使用UI後端層繪制每個節點。

關于順序:

上述這個過程是逐漸完成的,為了更好的使用者體驗,渲染引擎将會盡可能早的将内容呈現到螢幕上,并不會等到所有的html都解析完成之後再去建構和布局render樹。它是解析完一部分内容就顯示一部分内容,同時,可能還在通過網絡下載下傳過程遇到的其餘内容(比如css、js檔案,但遇到js檔案會阻塞頁面後續内容,css不會阻塞;另外圖檔的下載下傳優先級比較低,一般都會在整個頁面其他資源下載下傳完了才下載下傳圖檔)。

Javascript的加載和執行的特點:

(1)載入後馬上執行;

(2)執行時會阻塞頁面後續的内容(包括頁面的渲染、其它資源的下載下傳)。原因:因為浏覽器需要一個穩定的DOM樹結構,而JS中很有可能有 代碼直接改變了DOM樹結構,比如使用 document.write 或 appendChild,甚至是直接使用的location.href進行跳轉,浏覽器為了防止出現JS修 改DOM樹,需要重新建構DOM樹的情況,是以 就會阻塞其他的下載下傳和呈現。是以js通常放在頁面尾部,即body結束前。

如何了解Reflow(回流)和 Repaint(重繪)?

1) 當render tree中的一部分(或全部)因為元素的規模尺寸,布局,隐藏等改變而需要重新建構。這就稱為回流(reflow)。每個頁面至少需要一次回流,就是在頁面第一次加載的時候。在回流的時候,浏覽器會使渲染樹中受到影響的部分失效,并重新構造這部分渲染樹和layout,完成回流後,浏覽器會重新繪制受影響的部分到螢幕中,該過程稱為重繪。

2) 當render tree中的一些元素需要更新屬性,而這些屬性隻是影響元素的外觀,風格,而不會影響布局的,比如background-color。則就叫稱為重繪。

注意:回流必将引起重繪,而重繪不一定會引起回流。

3) 當頁面布局和幾何屬性改變時就需要回流。下述情況會發生浏覽器回流:

    a. 添加或者删除可見的DOM元素;

    b. 元素位置改變;

    c. 元素尺寸改變——邊距、填充、邊框、寬度和高度

    d. 内容改變——比如文本改變或者圖檔大小改變而引起的計算值寬度和高度改變;

    e. 頁面渲染初始化;

    f. 浏覽器視窗尺寸改變——resize事件發生時;

4) 聰明的浏覽器

從上個執行個體代碼中可以看到幾行簡單的JS代碼就引起了6次左右的回流、重繪。而且我們也知道回流的花銷也不小,如果每句JS操作都去回流重繪的話,浏覽器可能就會受不了。是以很多浏覽器都會優化這些操作,浏覽器會維護1個隊列,把所有會引起回流、重繪的操作放入這個隊列,等隊列中的操作到了一定的數量或者到了一定的時間間隔,浏覽器就會flush隊列,進行一個批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。

雖然有了浏覽器的優化,但有時候我們寫的一些代碼可能會強制浏覽器提前flush隊列,這樣浏覽器的優化可能就起不到作用了。當你請求向浏覽器請求一些 style資訊的時候,就會讓浏覽器flush隊列,比如:

    a. offsetTop, offsetLeft, offsetWidth, offsetHeight

    b. scrollTop/Left/Width/Height

    c. clientTop/Left/Width/Height

    d. width,height

    e. 請求了getComputedStyle(), 或者 IE的 currentStyle

當你請求上面的一些屬性的時候,浏覽器為了給你最精确的值,需要flush隊列,因為隊列中可能會有影響到這些值的操作。即使你擷取元素的布局和樣式資訊跟最近發生或改變的布局資訊無關,浏覽器都會強行重新整理渲染隊列。

5) 如何減少回流、重繪?

 ① 直接改變className,這樣能多條規則一次性改變;如果動态改變樣式,則使用cssText(考慮沒有優化的浏覽器)

 ② 讓要操作的元素進行”離線處理”,處理完後一起更新 

   a) 使用DocumentFragment進行緩存操作,引發一次回流和重繪;

   b) 使用display:none技術,隻引發兩次回流和重繪;( 隻是減少重繪和回流的次數,display:none 是會引起重繪并回流,相對來說,visibility: hidden隻會引起重繪 )

           c) 使用cloneNode(true or false) 和 replaceChild 技術,引發一次回流和重繪;

 ③ 不要經常通路會引起浏覽器flush隊列的屬性,如果你确實要通路,利用緩存

 ④ 讓元素脫離動畫流,減少回流的Render Tree的規模。舉例:$("#block1").animate({left:50}); (不過我沒了解)

   PS:如果對你有幫助,就順手點個贊吧~

本文轉自 藝晨光 51CTO部落格,原文連結:http://blog.51cto.com/ycgit/1959409,如需轉載請自行聯系原作者

繼續閱讀