你该了解的页面渲染原理与性能优化

首先,你应该了解的就是,浏览器是如何渲染一个页面的。

先看一个大致的流程图

它的总体流程是这样的:

1)浏览器解析这三个东西:

  • 解析HTML/XHTML/SVG,生成DOM树(事实上,Webkit有三个C++的类对应这三类文档以用于解析)。
  • 解析css文件产生CSS Rule树(css规则树)。
  • 解析javascript,通过DOM API和CSSOM API来操作DOM树和CSS Rule树。

2)解析完成后,浏览器会根据DOM树和CSS Rule树来构造渲染树(Rendering Tree)。

  • 渲染树并不完全等同于DOM树,因为一些display:none的东西就没必要放在渲染树中了。
  • CSS Rule树主要是为了完成匹配并把CSS Rule附加到渲染树上的每个DOM结点。
  • 然后,计算每个DOM节点的位置,这又叫layout和reflow过程。

3)最后通过调用操作系统Native GUI的API绘制(painting)。

抛去其中的细节,再简单一点的说法就是:DOM树解析->css解析->渲染(也就是构建渲染树以及最终呈现到浏览器上的过程)

这里 主要针对第三步的渲染过程进行一下讲解:

  1. 计算css样式,这一步对应着总体流程中的这句话,CSS Rule树主要是为了完成匹配并把CSS Rule附加到渲染树上的每个DOM结点,也就是说,最终的渲染树映射了 DOM 的结构。在渲染树中,每一个文本字符串都被当做一个独立的 renderer。每个渲染对象都包含了与之对应的计算过样式的DOM 对象(或者一个文本块)。换句话说,渲染树描述了 DOM 的直观的表现形式。
  2. 构建Render Tree。
  3. Layout – 定位坐标和大小,是否换行,各种position, overflow, z-index属性 ……
  4. 正式开画

需要注意的是:Javascript如果动态修改了DOM属性或是CSS属会导致重新Layout(Reflow),当然有些属性改变不会。

这里,这里重要要说两个概念,一个是Reflow,另一个是Repaint

Repaint(重绘)

当在页面上修改了一些不需要改变定位的样式的时候(比如background-color,border-color,visibility),浏览器只会将新的样式重新绘制给元素(这就叫一次“重绘”或者“重新定   义样式”)。这时只需要屏幕的一部分要重画。

  Reflow(重排)

   当页面上的改变影响了文档内容、结构或者元素定位时,就会发生重排(或称“重新布局”)。重排通常由以下改变触发:

  • DOM 操作(如元素增、删、改或者改变元素顺序)
  • 内容的改变,包括 Form 表单中文字的变化
  • 计算或改变 CSS 属性
  • 增加或删除一个样式表
  • 浏览器窗口的操作(改变大小、滚动窗口)
  • 激活伪类(如:hover状态)

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

可以看出,这两个动作对于浏览器的性能都有较大的影响,当然reflow的成本比repaint的成本高好多。那么,浏览器又是如何避免成本增加,从而优化渲染的呢?

浏览器如何优化渲染?

    1、浏览器尽最大努力限制重排的过程仅覆盖已更改的元素的区域。举个例子,一个 position 为 absolue 或 fixed 的元素的大小变化只影响它自身和子孙元素,而对一个 position 为 static 的元素做同样的操作就会引起所有它后面元素的重排。

2、当运行一段Jjavascript 代码的时候,浏览器会将一些修改缓存起来,然后当代码执行的时候,一次性的将这些修改执行。举例来说,这段代码会触发一次重绘和一次重排:

var bstyle = document.body.style; // cache
 bstyle.padding = "20px"; // reflow, repaint
 bstyle.border = "10px solid red"; //  再一次的 reflow 和 repaint
 bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
 bstyle.fontSize = "2em"; // reflow, repaint
 // new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode(‘dude!‘));

浏览器不会像上面那样,你每改一次样式,它就reflow或repaint一次。一般来说,浏览器会把这样的(都是设置style属性,而不涉及其他类似读取属性的操作)操作积攒一批,然后做一次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。

当然,我们可以通过改变书写习惯而做一些认为的性能优化:

实际优化建议

  • 创建合法的 HTML 和 CSS ,别忘了制定文件编码,Style 应该写在 head 标签中,script 标签应该加载 body 标签结束的位置
  • 试着简化和优化 CSS 选择器(这个优化点被大多数使用 CSS 预处理器的开发者忽略了)。将嵌套层数控制在最小。
  • 在你的脚本中,尽可能的减少 DOM 的操作。把所有东西都缓存起来,包括属性和对象(如果它可被重复使用)。进行复杂的操作的时候,最好操作一个“离线”的元素(“离线”元素的意思是与 DOM 对象分开、仅存在内存中的元素),然后将这个元素插入到 DOM 中。

例如:

1、使用documentFragment 对象在内存里操作DOM,类似以下的代码示例:

// Create the fragment
var fragment = document.createDocumentFragment();
//add DOM to fragment
for(var i = 0; i < 10; i++) {
    var spanNode = document.createElement("span");
    spanNode.innerHTML = "number:" + i;
    fragment.appendChild(spanNode);
}
//add this DOM to body
document.body.appendChild(spanNode);

        2、先把DOM给display:none(有一次reflow),然后你想怎么改就怎么改。比如修改100次,然后再把他显示出来。

3、clone一个DOM结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下

  • 不要一条一条地修改DOM的样式。与其这样,还不如预先定义好css的class,然后修改DOM的className
  • 尽可能的只对 position 为 absolute 或 fix 的元素做动画
  • 当滚动时禁用一些复杂的 :hover 动画是一个很好的主意(例如,给 body 标签加一个 no-hover 的 class
  • 千万不要使用table布局。因为可能很小的一个小改动会造成整个table的重新布局
时间: 2024-08-24 22:17:26

你该了解的页面渲染原理与性能优化的相关文章

JavaScript 如何工作:渲染引擎和性能优化技巧

翻译自:How JavaScript works: the rendering engine and tips to optimize its performance 这是探索 JavaScript 及其构建组件专题系列的第 11 篇.在识别和描述核心元素的过程中,我们分享了在构建 SessionStack 时使用的一些经验法则.SessionStack 是一个需要鲁棒且高性能的 JavaScript 应用程序,它帮助用户实时查看和重现它们 Web 应用程序的缺陷. 当构建 Web 应用程序时,

【转】Oracle Freelist和HWM原理及性能优化

文章转自:http://www.wzsky.net/html/Program/DataBase/74799.html 近期来,FreeList的重要作用逐渐为Oracle DBA所认识,网上也出现一些相关的讨论.本文以FreeList为线索对Oracle的存储管理的原理进行较深入的探讨,涉及Oracle段区块管理的 原理,FreeList算法等.而与FreeList密切相关的一个重用特性HWM,与sql性能密切相关,本文也作了原理分析介绍.在原理探讨的基础 上,介绍了常用的存储参数分析方法,并对

深入学习页面优化之页面渲染原理

拾人牙慧理解并整理之 直奔主题,要考虑到页面性能优化,必须得理解浏览器的渲染机制才行. 1.原理 渲染引擎在这里就不展开了,可自行搜索解决.下面说说渲染流程,大致是这样的: 浏览器在接收到服务器返回的html页面后, 浏览器开始构建DOM TREE,遇到CSS样式会构建CSS RULER TREE, 遇到javascript会通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree,解析完成后, 浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来

How Javascript works (Javascript工作原理) (十一) 渲染引擎及性能优化小技巧

个人总结:读完这篇文章需要20分钟,这篇文章主要讲解了浏览器中引擎的渲染机制. DOMtree       ----|   |---->  RenderTree CSSOMtree  ----| 这是 JavaScript 工作原理的第十一章. 迄今为止,之前的 JavaScript 工作原理系列文章集中于关注 JavaScript 语言本身的功能,在浏览器中的执行情况,如何优化等等. 然而,当在构建网络应用的时候,不仅仅只是编写自己运行的 JavaScript 代码.所编写的 JavaScri

浏览器页面渲染机制及简单优化

浏览器的内核是指支持浏览器运行的最核心的程序,分为两个部分: 1:渲染引擎 2:JS引擎 目前市面上常见的浏览器内核可以分为这四种:Trident(IE).Gecko(火狐).Blink(Chrome.Opera).Webkit(Safari) 页面加载过程要点如下: 1:浏览器根据DNS服务器得到域名的IP地址 2:向这个IP的机器发送HTTP请求 3:服务器收到.处理并返回HTTP请求 4:浏览器得到返回内容 浏览器渲染过程: 1:浏览器会解析三个东西: ①.HTML/SVG/XHTML,H

页面中的CSS性能优化

大型网站中会有多个CSS文件,性能优化是不要的.主要有以下几个方法: 一:压缩样式表: 通过构建工具压缩CSS文件,能够减少文件的大小,从而得到更快的下载.解析和执行.对于使用预处理器例如 Sass, Less, and Stylus, 你可以通过配置缩小编译输出的CSS代码. 二:合并多个CSS文件 因为每一个文件就是一个HTTP请求,合并CSS文件.文件数量的减少就会带来请求数量的减少和更快的页面加载速度. 三:使用link标签而不使用@inport 1 <link rel="styl

页面渲染原理

渲染流程 1.解析HTML文档 2.生成DOM树 3.生成渲染树.渲染树的节点只包括DOM树种可见节点,除了节点,渲染树含有节点的样式. 4.浏览器根据渲染树绘制页面. 与绘制相关的还有两个概念,回流和重绘 回流:元素的位置.大小或盒模型等改变影响了布局需要重新渲染部分或全部页面. 重绘:元素背景颜色等改变但不影响布局需要重新绘制部分页面. 可见,回流对性能的伤害大于重绘.且回流必然引起重绘. 引起回流的操作举例: DOM节点增删 display:none position变化 flow变化 窗

javascript的页面加载及性能优化(兼容IE7)

通常来说,window.onload就够用了,如果想加载多个事件,我们可以采取以下方式: window.onload = function(){        func1();        func2();        func3();        //更多加载事件……………… } 但是如果我们需要页面完全呈现前做一些东西呢,如通过脚本加载其他js文件,或在IE6实现fixed……这些东西就要用到domReady 了,domReady好像是jQuery的叫做,一个加载函数.在W3C的草稿中

单页面系统的一些性能优化

1:初次进入系统的新用户 首次进入该系统的用户,没有任何的文件缓存.进入系统后加载index.html 会将所有的文件(图片.js.css)下载下来 耗时在3.3s左右.之后进入系统 只会额外加载一些页面的图片,不会再加载js.css文件. 2:已经进过该系统的老用户,且系统未更新之前 用户本地的文件都已经被缓存(图片.css.js),在系统更新之前,所有的文件都没有更改,用户再进入系统时,速度会在500ms之内,可以从下图看到,所有的文件加载速度都是为0的. 3:已经进入过该系统的老用户,且系