原文地址:http://ce.sysu.edu.cn/hope/Item/140355.aspx

作者:陈古松 来源:本站原创 发布时间:2015-03-14 更新时间:2015-03-14  点击数:612

一、渲染引擎的分离 

        浏览器中通常会把DOM和JavaScript引擎独立实现。

(1)IE:javascript实现是JScript,DOM实现为Trident。

(2)Safari:javascript引擎SquirrelFish,DOM渲染采用的是Webkit中的WebCore实现的。

(3)Chrome:javascript引擎为V8,DOM渲染采用的是Webkit中的WebCore实现的。

(4)Firefox:javascript引擎名为SpiderMonkey,新版名为TraceMonkey,DOM渲染采用的是Gecko 。

二、分离的后果

两个相互独立的功能只能通过接口彼此连接,但是这样会产生性能消耗,这好比两个独立的岛屿只能通过桥梁来沟通而不幸的是这个桥梁是要收费的。
         DOM访问次数越多,代码运行速度越慢。所以一般经验法则是:减少DOM的次数,把运算尽量保留在ECMAScript这一块处理。

三、HTML页面绘制过程

浏览器下载完页面中所有组件(html、js、css)后,解析生成两个内部数据结构:DOM树(表示页面结构)、渲染树(表示DOM节点如何显示)。

DOM树中每一个需要显示的节点在渲染树中至少存在一个对应的节点(隐藏的DOM元素在渲染树中没有对应的节点)。渲染树中的节点被称为“帧”或者“盒”,可理解为页面元素中一个具有padding、margin、border、position的盒子。一旦DOM和渲染树构建完成,浏览器就开始绘制页面元素。

 四、重绘(repaint)和重排(repaint)

当DOM的变化影响元素的几何属性(宽和高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会受到影响。

浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树,这个过程称为重排。 完成重排后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘 。

并不是所有的DOM变化都会影响几何属性(如背景的改变),这样只会发生重绘。

五:重排何时发生?

1、添加或删除可见的DOM元素 ;

2、元素位置的改变 ;

3、元素尺寸改变 ;

4、内容改变 ;

5、页面渲染器初始化;

6、浏览器窗口尺寸的改变 。

六、渲染树变化的排队与刷新

由于每次重排都会产生计算消耗,所以大多数浏览器都通过队列化修改并批量执行来优化重排过程。

但是有的属性和方法需要返回最新的布局信息,因此浏览器不得不处理渲染队列中的"待处理变化"并触发重排以返回最新的值,这样就导致了队列的刷新。这些属性有:

offsetTop、offsetLeft、offsetWidth、offsetHeight;
        scrollTop、scrollLeft、scrollWidth、scrollHeight;
        clientTop、clientLeft、clientWidth、clientHeight;
        getComputedStyle()(currentStyle in IE)。

七、最小化重绘和重排

重绘和重排代价可能非常昂贵,因此一个好的提高程序响应速度的策略就是减少此类操作的发生。为了减少发生次数,应该多次合并对DOM和样式的修改,然后一次处理掉。

1、改变样式:

(1)利用cssText属性合并所有改变,然后一次性写入。

(2)修改html元素中对应的class名,利用class替换样式(不依赖于运算逻辑和计算的情况下)。

2、批量修改DOM:

(1)步骤:使元素脱离文档流 ->对其应用多重改变 -> 把元素带回到文档中。

(2)脱离文档流的方式:

a、隐藏元素,应用修改,重新显示;

b、使用文档片段(document fragment)在当前DOM之外构建一个子树,再插回去;

c、将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换回去;

(3)实例: 假设我们需要用已有数据对一个已有的ul列表插入子项。html片段为:

<ul id="list">
   <li><a href="http://www.baidu.com">百度</a></li>
</ul>

数据为:

var data = [
{
"name":"Google",
"utl":"http://google.com"
},
{
"name":"Apple",
"utl":"http://apple.com"
}
]

更新节点的通用函数:

function appendDataToElement(node,data){
var a,li,doc = document
for(var i=0,max = data.length;i<max;i++){
a = doc.createElement('a');
a.href=data[i].url;
a.appendChild(doc.createTextNote(data[i].name));
li = doc.createElement('li');
li.appendChild(a);
node.appendChild(li);
}
}

最常用但低效的执行:

var list = document.getElementById("list");
appendDataToElement(list,data);

使用display属性减少重排:

var list = document.getElementById("list");
list.style.display = 'none';
appendDataToElement(list,data);
list.style.display = 'block';

使用文档片段减少重排(推荐):

var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
appendDataToElement(fragment,data);
list.appendChild(fragment);

采用副本方式减少重排:

var old = document.getElementById("list");
var clone = old.cloneNode(true);
appendDataToElement(clone,data);
old.parentNode.replaceChild(clone,old);

Javascript之DOM性能优化的更多相关文章

  1. JavaScript大杂烩17 - 性能优化

    在上一节推荐实践中其实很多方面是与效率有关的,但那些都是语言层次的优化,这一节偏重学习大的方面的优化,比如JavaScript脚本的组织,加载,压缩等等. 当然在此之前,分析一下浏览器的特征还是很有意 ...

  2. web前端优化--DOM性能优化

    1.DOM访问与修改的优化: DOM访问是有代价的,修改DOM则会引起DOM的重绘与重排,而这两种操作会消耗性能. (1)缓存DOM:将频繁访问的对象或属性使用变量缓存起来,每次访问的时候,直接使用变 ...

  3. Dom基础(二):Dom性能优化

    一.尽量将DOM查询做缓存 1 let pElements = document.getElementById('div1') //将dom缓存 2 3 for(let i=0:i<pEleme ...

  4. (O)WEB:前端网站性能优化(原创)

    *从理论.实战编码.实战调试3个方面学习前端性能优化(包括页面加载时间和页面流畅度): -------------------------------理论----------------------- ...

  5. (转)Javascript的DOM操作 - 性能优化

    转载:https://my.oschina.net/blogshi/blog/198910 摘要: 想稍微系统的说说对于DOM的操作,把Javascript和jQuery常用操作DOM的内容归纳成思维 ...

  6. JavaScript性能优化

    如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...

  7. 前端性能优化--为什么DOM操作慢?

    作为一个前端,不能不考虑性能问题.对于大多数前端来说,性能优化的方法可能包括以下这些: 减少HTTP请求(合并css.js,雪碧图/base64图片) 压缩(css.js.图片皆可压缩) 样式表放头部 ...

  8. javascript性能优化-repaint和reflow

    repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲 ...

  9. 摘:JavaScript性能优化小知识总结

    原文地址:http://www.codeceo.com/article/javascript-performance-tips.html JavaScript的性能问题不容小觑,这就需要我们开发人员在 ...

随机推荐

  1. node.js遇到的问题

    1.cann't find module 'request'   不能找到’request' 模块 解决方法:找到项目的根路径,cd到该路径,运行命令 npm install request 2.no ...

  2. Hibernate映射 --- 自身跟自身的一对多关联

      自身跟自身的一对多关联 什么时候会出现自身一对多关系呢?下面举个例子. 淘宝店里商品分类,一级分类:家用电器,个人化妆,运动户外等 家用电器下面二级分类:大家电,生活电器,厨房电器等 二级分类大家 ...

  3. web开发中的两把锁之数据库锁:(高并发--乐观锁、悲观锁)

    这篇文章讲了 1.同步异步概念(消去很多疑惑),同步就是一件事一件事的做:sychronized就是保证线程一个一个的执行. 2.我们需要明白,锁机制有两个层面,一种是代码层次上的,如Java中的同步 ...

  4. ifream框架角色切换

    js受制于单个页面,用ifream框架做web系统,会遇到角色切换菜单刷新的问题,我就来讲一下我的思路: 用户登录时将用户角色放入session中,以角色id为key,权限为值,角色切换时将相应角色i ...

  5. 为什么要用lock 【readonly】object?为什么不要lock(this)?

    一. 为什么要用lock,lock了什么? 当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待.但当不同的线程都需要访问某个资源的时候,就需要同步机制了.也就是说 ...

  6. Angular4.x 自定义搜索组件

    Angular4 随笔(三)  ——自定义搜索组件 1.简介 本组件主要是实现了搜索功能,主要是通过父子组件传值实现. 基本逻辑: 1.创建一个搜索组件,如:ng g component  searc ...

  7. python常用模块-01

    1. 简单了解模块 写的每一个py文件都是一个模块. 还有一些我们一直在使用的模块 buildins 内置模块. print, input random 主要是和随机相关的内容 random()    ...

  8. python中matplotlib.pyplot中cm的属性

    https://matplotlib.org/gallery/color/colormap_reference.html

  9. BZOJ2957: 楼房重建(分块)

    题意 题目链接 Sol 自己YY出了一个\(n \sqrt{n} \log n\)的辣鸡做法没想到还能过.. 可以直接对序列分块,我们记第\(i\)个位置的值为\(a[i] = \frac{H_i}{ ...

  10. js-语言精粹-函数记忆

    函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算.这种优化方式被称为记忆(memoization).JavaScript的对象和数组要实现这种优化是非常方便的. 比如说,我们想要一个递 ...