首先什么是DOM?为什么慢?

DOM:文档对象模型,是一个独立于语言的,用于操作XML和HTML文档的程序接口(API)

用脚本进行DOM操作的代价很昂贵。那么,怎样才能提高程序的效率?

1、DOM访问与修改

访问DOM元素是有代价的,修改元素代价更是昂贵,因为它会导致浏览器重新计算页面的几何变化(重排和重绘)。

尤其是在循环中访问或者修改元素,看下面两段代码:

var times = 15000;
console.time(1);
for(var i = 0; i < times; i++) {
  document.getElementById('myDiv1').innerHTML += 'a';
}
console.timeEnd(1); // 2846.700ms

这段代码的问题在于,每次循环迭代,该元素就会被访问两次,一次读取,一次重写。

console.time(2);
var str = '';
for(var i = 0; i < times; i++) {
  str += 'a';
}
document.getElementById('myDiv2').innerHTML = str;
console.timeEnd(2); // 1.046ms

这种方法明显效率更高,循环结束后一次性写入。

1.1、HTML集合

HTML是包含了DOM节点引用的类数组对象。

Document.getElementsByTagName(); document.links 等 获取的都是一个集合。是个类似数组的列表,但不是真正的数组(因为没有push或slice之类的方法),但提供了一个length的属性。可以通过下标访问元素。

高性能JavaScript指出在相同内容和数量下,遍历一个数组的速度明显快于遍历一个HTML集合。

例子

console.time(0);
var lis0 = document.getElementsByTagName('li');
var str0 = '';
for(var i = 0; i < lis0.length; i++) {
  str0 += lis0[i].innerHTML;
}
console.timeEnd(0); // 0.974ms console.time(1);
var lis1 = document.getElementsByTagName('li');
var str1 = '';
for(var i = 0, len = lis1.length; i < len; i++) {
  str1 += lis1[i].innerHTML;
}
console.timeEnd(1); // 0.664ms

注意:因为额外的步骤带来消耗,而且会多遍历一次集合,因此需结合实际情况下使用数组拷贝是否有帮助。

1.2、选择器API

如果是处理大量组合查询,使用querySelectorAll的话会更效率。

var elements = document.querySelectorAll('#menu a');
var elementss = document.querySelectorAll('div.warning, div.notice');

2、重绘和重排

当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。

完成重排后,浏览器会重新绘制受影响的部分到屏幕,该过程称为重绘。

2.1、重排何时发生

每次重排,必然会导致重绘,那么,重排会在哪些情况下发生?

1.添加或者删除可见的DOM元素

2.元素位置改变

3.元素尺寸的改变(padding、margin、border、height、width)

4.内容改变(文本改变或图片尺寸改变)

5.页面渲染初始化(这个无法避免)

6.浏览器窗口尺寸改变

不间断地改变浏览器窗口大小,导致UI反应迟钝(某些低版本IE下甚至直接挂掉),正是一次次的重排重绘导致的!

改变样式

思考下面代码:

var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';

示例中,元素的三个样式被改变,而且每一个都会影响元素的几何结构。在最糟糕的情况下,这段代码会触发三次重排(大部分现代浏览器为此做了优化,只会触发一次重排)。

优化

var el = document.getElementById('mydiv');

// method_1:使用cssText属性:
el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px'; // method_2:修改类名:
el.className = 'anotherClass';

2.2、批量修改DOM

看如下代码,考虑一个问题:

<ul id='fruit'>
<li> apple </li>
<li> orange </li>
</ul>

如果代码中要添加内容为peach、watermelon两个选项,你会怎么做?

var lis = document.getElementById('fruit');
var li = document.createElement('li');
li.innerHTML = 'peach';
lis.appendChild(li); var li = document.createElement('li');
li.innerHTML = 'watermelon';
lis.appendChild(li);

很容易想到如上代码,但是很显然,重排了两次,怎么破?这时,fragment元素就有了用武之地了。

var fragment = document.createDocumentFragment();

var li = document.createElement('li');
li.innerHTML = 'peach';
fragment.appendChild(li); var li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li); document.getElementById('fruit').appendChild(fragment);

createdocumentfragment()方法创建了一虚拟的节点对象,节点对象包含所有属性和方法。

它的设计初衷就是为了完成这类任务——更新和移动节点。

3、事件委托(Event Delegation)

当页面中有大量的元素,并且这些元素都需要绑定事件处理器。每绑定一个事件处理器都是有代价的,要么加重了页面负担,要么增加了运行期的执行时间。再者,事件绑定会占用处理时间,而且浏览器需要跟踪每个事件处理器,这也会占用更多的内存。还有一种情况就是,当这些工作结束时,这些事件处理器中的绝大多数都是不再需要的(并不是100%的按钮或链接都会被用户点击),因此有很多工作是没有必要的。

使用事件委托,只需要给外层元素绑定一个处理器,就可以处理在其子元素上触发的所有事件。

有以下几点需要注意:

1.访问事件对象,判断事件源

2.按需取消文档树中的冒泡

3.阻止默认动作

小结

访问DOM是现代WEB应用的重要部分,但每次穿越连接DOM和ECMAScript之间都会消耗性能

1.最小化DOM访问次数,尽可能在JavaScript端处理

2.如果需要多次访问某个DOM节点,可以使用局部变量储存它的引用。

3.如果要操作一个HTML元素集合,建议把它拷贝到一个数组中

4.如果可能的话,使用速度更快的API 比如 querySelectorAll 和 firstElementChild

5.使用事件委托来减少事件处理器的数量

高性能JavaScript(DOM编程)的更多相关文章

  1. 高性能JavaScript DOM编程

    我们知道,DOM是用于操作XML和HTML文档的应用程序接口,用脚本进行DOM操作的代价很昂贵.有个贴切的比喻,把DOM和JavaScript(这里指ECMScript)各自想象为一个岛屿,它们之间用 ...

  2. 读书笔记:JavaScript DOM 编程艺术(第二版)

    读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...

  3. JavaScript DOM 编程艺术·setInterval与setTimeout的动画实现解析

    先贴上moveElement()函数的大纲,为了方便观看,删了部分代码,完整版粘到文章后面. function moveElement(elementID,final_x,final_y,interv ...

  4. JavaScript DOM 编程艺术(第2版)读书笔记(1)

    JavaScript 简史 JavaScript 是Netscape公司与Sun公司合作开发的.在 JavaScript 1.0发布时,Netscape Navigator主宰着浏览器市场.微软在推出 ...

  5. JavaScript DOM编程艺术学习笔记(一)

    嗯,经过了一周的时间,今天终于将<JavaScript DOM编程艺术(第2版)>这本书看完了,感觉受益匪浅,我和作者及出版社等等都不认识,无意为他们做广告,不过本书确实值得一看,也值得推 ...

  6. JavaScript DOM编程艺术第一章:JavaScript简史

    本系列的博客是由本人在阅读<JavaScript DOM编程艺术>一书过程中做的总结.前面的偏理论部分都是书中原话,觉得有必要记录下来,方便自己翻阅,也希望能为读到本博客的人提供一些帮助, ...

  7. 《JavaScript dom 编程艺术》 placeholder占位符IE8兼容办法。

    在<JavaScript dom 编程艺术>第11章学来的. 相对于用JavaScript替换文本框的提示语句 <!DOCTYPE html> <html lang=&q ...

  8. 《javascript dom编程艺术》笔记(一)——优雅降级、向后兼容、多个函数绑定onload函数

    刚刚开始自学前端,如果不对请指正:欢迎各位技术大牛指点. 开始学习<javascript dom编程艺术>,整理一下学习到的知识.今天刚刚看到第六章,记下get到的几个知识点. 优雅降级 ...

  9. 《JavaScript DOM 编程艺术》

    前几天京东买了一本书,在豆瓣上好评如潮,买下了啃一啃,书名<JavaScript DOM 编程艺术>,在好好深造一下javaScript.一边啃,一边敲.当然应该要做好笔记.一些简单的就看 ...

  10. JavaScript DOM编程艺术读后感(1)—— 平稳退化

    最近,在读<JavaScript DOM编程艺术(第二版)>这本书,想着将自己的读后感记录下来,作为记忆吧. 其实我并不是最近才刚开始读这本书的,我读了有一段时间了.我是一名web前端开发 ...

随机推荐

  1. odoo开发笔记 -- 视图继承扩展

    参考: http://www.jeffzhang.cn/Odoo-Notes-2/ http://blog.csdn.net/zhangfeng1133/article/details/4693517 ...

  2. 刚破了潘金莲的身份信息(图片文字识别),win7、win10实测可用(免费下载)

    刚破了潘金莲的身份信息(图片文字识别),win7.win10实测可用 效果如下: 证照,车牌.身份证.名片.营业执照 等图片文字均可识别 电脑版 本人出品 大小1.3MB 下载地址:https://p ...

  3. Strom的trident单词计数代码

    /** * 单词计数 */ public class LocalTridentCount { public static class MyBatchSpout implements IBatchSpo ...

  4. 自然语言处理(英文演讲)_2-gram

    这里利用2-gram模型来提取一篇英文演讲的初略的主题句子,这里是英文演讲的的链接:http://pythonscraping.com/files/inaugurationSpeech.txt n-g ...

  5. SpringBoot用@ConfigurationProperties获取配置文件值

    SpringBoot的配置文件有yml和properties两种,看一些文章说yml以数据为中心,比较好.个人觉得properties更好用,所以这里以properties格式为例来说. 我们都知道@ ...

  6. 使用java调用fastDFS客户端进行静态资源文件上传

    一.背景 上篇博客我介绍了FastDFS的概念.原理以及安装步骤,这篇文章我们来聊一聊如何在java中使用FastDFSClient进行静态资源的上传. 二.使用步骤 1.开发环境 spring+sp ...

  7. Python核心编程 | 装饰器

        装饰器是程序开发的基础知识,用好装饰器,在程序开发中能够提高效率 它可以在不需要修改每个函数内部代码的情况下,为多个函数添加附加功能,如权限验证,log日志等   涉及点:   1.先梳理一下 ...

  8. mysql-unsha1:在未知密码情况下,登录任意MYSQL数据库

    摘要 这个POC用于在不知道明文密码的情况下对启用了密码安全认证插件(默认开启插件:mysql_native_password)的MYSQL数据库进行登录. 前提条件为: 1.为了获取到已知用户的ha ...

  9. 安装Windows 8.1过程中出现的各种问题(无损从MBR转GPT磁盘、不能定位已有分区)

    这个周末就安装了个系统,本以为一个小时就能搞定,没想到花费了将近一天. 我的机子是6G内存.500G硬盘,原装系统是Windows 7,现在想换成Windows 8.1,于是下载了64位的Window ...

  10. 资深程序员的Metal入门教程总结

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由落影发表于云+社区专栏 正文 本文介绍Metal和Metal Shader Language,以及Metal和OpenGL ES的差异 ...