这两天比较闲,写了两篇关于JS性能缺陷与解决方案的文章(《JS特性性能缺陷及JIT的解决方案》,《Javascript垃圾回收浅析》),主要描述了untyped,GC带来的问题与JIT引擎的解决方案。但相对于Js引擎的问题,我认为DOM导致的性能问题更值得关注。

一.Dom的性能瓶颈及原因

1. 为什么是DOM

标准的xml/html的文本解析协议,常见的有DOM与SAX。在解析速度及内存占用上,SAX比DOM有优势,但为什么浏览器选择DOM解析html?

(1)DOM VS SAX

SAX提供一次性解析文本,不生成对象,Iterator模式访问元素,event-based,PUSH模式触发,简单说:App需要向Parser注册,当Parser遍历xml时,触发调用APP 。想深入体验,用下javax.xml.parsers.SAXParser。这里说个题外话,改进版StAX是PULL模式,但这都不重要了,重要是:一次性文本解析,不生成对象。

DOM解析文本后,生成DOM树。即:一次性文本解析,生成对象。

(2)浏览器选择了DOM

单次效率DOM不如SAX,但SAX不生成对象,浏览器很多操作很难满足,比如:元素定位,元素样式渲染……所以DOM是必然之选。

2. DOM的性能问题

【1】核心问题

当解析的html文件很大时,生成DOM树占用内存较大,同时遍历(不更新)元素耗时也更长。但这都不是重点,DOM的核心问题是:DOM修改导致的页面重绘、重新排版!重新排版是用户阻塞的操作,同时,如果频繁重排,CPU使用率也会猛涨!

DOM操作会导致一系列的重绘(repaint)、重新排版(reflow)操作。为了确保执行结果的准确性,所有的修改操作是按顺序同步执行的。大部分浏览器都不会在JavaScript的执行过程中更新DOM。相应的,这些浏览器将对对 DOM的操作放进一个队列,并在JavaScript脚本执行完毕以后按顺序一次执行完毕。也就是说,在JavaScript执行的过程,直到发生重新排版,用户一直被阻塞。

    一般的浏览器中(不含IE),repaint的速度远快于reflow,所以避免reflow更重要

导致repaint、reflow的操作

 * DOM元素的添加、修改(内容)、删除( Reflow + Repaint)

    * 仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)

    * 应用新的样式或者修改任何影响元素外观的属性

    * Resize浏览器窗口、滚动页面

    * 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE))

【2】其他

某些Javascript框架中,CSS选择器,如:var el = $('.hyddd');由于IE6、7不支持,所以Javascript框架必须通过遍历整个DOM树来寻找对象。

二. 针对DOM问题,Javascript的应对方案

1. 针对repaint、reflow,Nicholas 大叔在他的《Speed up your JavaScript, Part 4》做了详细介绍,这里我也整理一下:

解决问题的关键是:减少因DOM操作,引起的reflow。Nicholas总结了一些方法:

【1】在DOM外,执行尽量多的变更操作。Demo:

// 不好的做法
for (var i=0; i < items.length; i++){
var item = document.createElement("li");
item.appendChild(document.createTextNode("Option " + i);
list.appendChild(item);
}   
// 更好的做法
// 使用容器存放临时变更, 最后再一次性更新DOM
var fragment = document.createDocumentFragment();
for (var i=0; i < items.length; i++){
var item = document.createElement("li");
item.appendChild(document.createTextNode("Option " + i);
fragment.appendChild(item);
}
list.appendChild(fragment);

【2】操作DOM前,先把DOM节点删除或隐藏,因为隐藏的节点不会触发重排。Demo如下:

list.style.display = "none";
for (var i=0; i < items.length; i++){
var item = document.createElement("li");
item.appendChild(document.createTextNode("Option " + i);
list.appendChild(item);
}
list.style.display = "";

【3】一次性,修改样式属性。Demo如下:

// 不好的做法
// 这种做法会触发多次重排
element.style.backgroundColor = "blue";
element.style.color = "red";
element.style.fontSize = "12em";
// 更好的做法是,把样式都放在一个class下
.newStyle {
background-color: blue;
color: red;
font-size: 12em;
}
element.className = "newStyle";

【4】使用缓存,缓存临时节点。

// 不好的做法
document.getElementById("myDiv").style.left = document.getElementById("myDiv").offsetLeft +
document.getElementById("myDiv").offsetWidth + "px";
// 更好的做法
var myDiv = document.getElementById("myDiv");
myDiv.style.left = myDiv.offsetLeft + myDiv.offsetWidth + "px";

2. 针选择其的问题,我只能说:没办法…… : (

三. 参考资源

1.《Web 2.0应用客户端性能问题十大根源

2. 《Speed up your JavaScript, Part 4

DOM性能瓶颈与Javascript性能优化的更多相关文章

  1. JavaScript性能优化

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

  2. javascript性能优化-repaint和reflow

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

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

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

  4. JavaScript性能优化小窍门汇总(含实例)

    在众多语言中,JavaScript已经占有重要的一席之地,利用JavaScript我们可以做很多事情 , 应用广泛.在web应用项目中,需要大量JavaScript的代码,将来也会越来越多.但是由于J ...

  5. JavaScript性能优化小知识总结(转)

    JavaScript的性能问题不容小觑,这就需要我们开发人员在编写JavaScript程序时多注意一些细节,本文非常详细的介绍了一下JavaScript性能优化方面的知识点,绝对是干货. 前言 一直在 ...

  6. 前端性能优化--为什么DOM操作慢? 浅谈DOM的操作以及性能优化问题-重绘重排 为什么要减少DOM操作 为什么要减少操作DOM

    前端性能优化--为什么DOM操作慢?   作为一个前端,不能不考虑性能问题.对于大多数前端来说,性能优化的方法可能包括以下这些: 减少HTTP请求(合并css.js,雪碧图/base64图片) 压缩( ...

  7. JavaScript性能优化篇js优化

    JavaScript性能优化篇js优化   随着Ajax越来越普遍,Ajax引用的规模越来越大,Javascript代码的性能越来越显得重要,我想这就是一个很典型的例子,上面那段代码因为会被频繁使用, ...

  8. Javascript 性能优化的一点技巧

    把优秀的编程方式当成一种习惯,融入到日常的编程当中.下图是今天想到的一点Javascript 性能优化的技巧,分享一下,抛砖引玉.

  9. 高频dom操作和页面性能优化(转载)

    作者:gxt19940130 原文:https://feclub.cn/post/content/dom 一.DOM操作影响页面性能的核心问题 通过js操作DOM的代价很高,影响页面性能的主要问题有如 ...

随机推荐

  1. textarea元素只设置高可变,宽固定

    网上查了一下多数只告诉怎么禁止拖动,好在编辑器提示了所有的属性,在此记录一下 textarea{ resize: vertical; } 还有其它的属性

  2. JS判断字符串长度(中文长度为2,英文长度为1)

    目的:计算字符串长度(英文占1个字符,中文汉字占2个字符) 方法一: String.prototype.gblen = function() { var len = 0; for (var i=0; ...

  3. STL~heap

    1.定义 堆:若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树 树中任一非叶子结点的关键字均不大于(或不小于)其子结点的关键字.分为大根数(默认 ...

  4. LUA中将未分类数据分为测试集和训练集

    require 'torch' require 'image' local setting = {parent_root = '/home/pxu/image'} function list_chil ...

  5. java中面向对象的一些知识(二)

    一. 封装的讲解 什么是封装?为什么要封装?怎么实现封装? 封装的目的是为了提高程序的安全性.封装就是把不想让第三者看的属性,方法隐藏起来. 封装的实现方法是: 1.修改属性的可见性,限制访问. 2. ...

  6. python3 黑板客爬虫闯关游戏(三)

    第三关,先登录,再猜密码,这关难度较第二关大幅增加,要先去注册一个登录账号,然后打开F12,多登录几次,观察headers数据的变化 给出代码,里面注释很详细 import urllib.reques ...

  7. 如何方便的保存WinForm窗体控件的位置大小等等配置信息

    由于分辨率.屏幕主题.字体大小的不同,窗体显示效果在不同机器上不尽相同.窗体的弹性设计并不能满足多样的需求.为保证在各种情况下,能有满意的效果.窗体的多样显示方式能改变,并且保存.载入配置,显得很重要 ...

  8. java注解处理

    1.自定义注解类型   package com.yc.annotation; import java.lang.annotation.ElementType; import java.lang.ann ...

  9. BFS_Maze_求解迷宫最短路径

    /* 10 10 #.######.# ......#..# .#.##.##.# .#........ ##.##.#### ....#....# .#######.# ....#..... .## ...

  10. iOSIPV6简单测试环境搭建

    应苹果官方要求,iOS应用必须适配IPV6才能通过审核,这里分享一个简单的ipv6测试方法 一.工具原料 1.1 Mac电脑一台 1.2 iPhone手机两部 1.3 数据线一根 二.步骤方法 2.1 ...