zoukankan      html  css  js  c++  java
  • 浏览器渲染及相关性能

    一、浏览器渲染

    1、网页的生成过程

    1.解析HTML/XHML/SVG生成DOM树

    2.解析css生成CSSOM (css规则树)

    3.结合DOM和CSSOM,生成一棵渲染树(Render Tree)(包含每个节点的视觉信息)。

      Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。

      CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。

      CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,你就会在N多地方看到很多人都告诉你,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去,……

    4.生成布局(layout),计算元素大小、节点位置。即将所有渲染树的所有节点进行平面合成。

    5.最后通过调用操作系统Native GUI的API绘制。

    2.重排(reflow)和 重绘(repaint)

    • Repaint——屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。
    • Reflow——意味着元件的几何尺寸变了,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。这就是Reflow,或是Layout。(HTML使用的是flow based layout,也就是流式布局,所以,如果某元件的几何尺寸发生了变化,需要重新布局,也就叫reflow )reflow 会从<html>这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置,在reflow过程中,可能会增加一些frame,比如一个文本字符串必需被包装起来。

    三、对于性能的影响

    当你增加、删除、修改DOM结点时,会导致Reflow或Repaint

    • 当你移动DOM的位置,或是搞个动画的时候。
    • 当你修改CSS样式的时候。
    • 当你Resize窗口的时候(移动端没有这个问题),或是滚动的时候。
    • 当你修改网页的默认字体时。
    • 注:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。

      多说两句关于滚屏的事,通常来说,如果在滚屏的时候,我们的页面上的所有的像素都会跟着滚动,那么性能上没什么问题,因为我们的显卡对于这种把全屏像素往上往下移的算法是很快。但是如果你有一个fixed的背景图,或是有些Element不跟着滚动,有些Elment是动画,那么这个滚动的动作对于浏览器来说会是相当相当痛苦的一个过程。你可以看到很多这样的网页在滚动的时候性能有多差。因为滚屏也有可能会造成reflow。

      基本上来说,reflow有如下的几个原因:

      • Initial。网页初始化的时候。
      • Incremental。一些Javascript在操作DOM Tree时。
      • Resize。其些元件的尺寸变了。
      • StyleChange。如果CSS的属性发生变化了。
      • Dirty。几个Incremental的reflow发生在同一个frame的子树上。

    四、提高性能的九个技巧

    第一条,DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。

    一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow,这又叫异步reflow或增量异步reflow 。但是有些情况浏览器是不会这么做的,比如:resize窗口,改变了页面默认的字体,等。对于这些操作,浏览器会马上进行reflow。

    但是有些时候,我们的脚本会阻止浏览器这么干,比如:如果我们请求下面的一些DOM值:

    1. offsetTop, offsetLeft, offsetWidth, offsetHeight
    2. scrollTop/Left/Width/Height
    3. clientTop/Left/Width/Height
    4. IE中的 getComputedStyle(), 或 currentStyle

    因为,如果我们的程序需要这些值,那么浏览器需要返回最新的值,而这样一样会flush出去一些样式的改变,从而造成频繁的reflow/repaint。

    第二条,如果某个样式是通过重排得到的,那么最好缓存结果。避免下一次用到的时候,浏览器又要重排。

    第三条,不要一条条地改变样式,而要通过改变class,或者csstext属性,一次性地改变样式。

    第四条,尽量使用离线DOM,而不是真实的网面DOM,来改变元素样式。比如,操作Document Fragment对象,完成后再把这个对象加入DOM。再比如,使用 cloneNode() 方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。

    第五条,先将元素设为display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。

    第六条,position属性为absolutefixed的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。

    第七条,只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden的元素只对重绘有影响,不影响重排。

    第八条,使用虚拟DOM的脚本库,比如React等。

    第九条,使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染

  • 相关阅读:
    背水一战 Windows 10 (61)
    背水一战 Windows 10 (60)
    背水一战 Windows 10 (59)
    背水一战 Windows 10 (58)
    背水一战 Windows 10 (57)
    背水一战 Windows 10 (56)
    背水一战 Windows 10 (55)
    背水一战 Windows 10 (54)
    背水一战 Windows 10 (53)
    背水一战 Windows 10 (52)
  • 原文地址:https://www.cnblogs.com/xinup/p/4876180.html
Copyright © 2011-2022 走看看