for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; document.body.appendChild(el); } //可以替换为: var frag = document.createDocumentFragment(); for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag);
使用一次innerHTML赋值代替构建dom元素
对于大的DOM更改,使用innerHTML要比使用标准的DOM方法创建同样的DOM结构快得多。
var frag = document.createDocumentFragment(); for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag); //可以替换为: var html = []; for (var i = 0; i < 1000; i++) { html.push('<p>' + i + '</p>'); } document.body.innerHTML = html.join('');
通过模板元素clone,替代createElement
很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。通常我们可能会使用字符串直接写HTML来创建节点,其实这样做,1无法保证代码的有效性2字符串操作效率低,所以应该是用document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,应该先准备一个样板节点
var frag = document.createDocumentFragment(); for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag); //替换为: var frag = document.createDocumentFragment(); var pEl = document.getElementsByTagName('p')[0]; for (var i = 0; i < 1000; i++) { var el = pEl.cloneNode(false); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag);
使用firstChild和nextSibling代替childNodes遍历dom元素
var nodes = element.childNodes; for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; //…… } //可以替换为: var node = element.firstChild; while (node) { //…… node = node.nextSibling;
删除DOM节点
删除dom节点之前,一定要删除注册在该节点上的事件,不管是用observe方式还是用attachEvent方式注册的事件,否则将会产生无法回收的内存。另外,在removeChild和innerHTML=''二者之间,尽量选择后者. 因为在sIEve(内存泄露监测工具)中监测的结果是用removeChild无法有效地释放dom节点
使用事件代理
任何可以冒泡的事件都不仅仅可以在事件目标上进行处理,目标的任何祖先节点上也能处理,使用这个知识就可以将事件处理程序附加到更高的地方负责多个目标的事件处理,同样,对于内容动态增加并且子节点都需要相同的事件处理函数的情况,可以把事件注册提到父节点上,这样就不需要为每个子节点注册事件监听了。另外,现有的js库都采用observe方式来创建事件监听,其实现上隔离了dom对象和事件处理函数之间的循环引用,所以应该尽量采用这种方式来创建事件监听
重复使用的调用结果,事先保存到局部变量
//避免多次取值的调用开销 var h1 = element1.clientHeight + num1; var h2 = element1.clientHeight + num2; //可以替换为: var eleHeight = element1.clientHeight; var h1 = eleHeight + num1; var h2 = eleHeight + num2;
注意NodeList
最小化访问NodeList的次数可以极大的改进脚本的性能
var images = document.getElementsByTagName('img'); for (var i = 0, len = images.length; i < len; i++) { }
编写JavaScript的时候一定要知道何时返回NodeList对象,这样可以最小化对它们的访问
进行了对getElementsByTagName()的调用
获取了元素的childNodes属性
获取了元素的attributes属性
访问了特殊的集合,如document.forms、document.images等等
要了解了当使用NodeList对象时,合理使用会极大的提升代码执行速度
优化循环
可以使用下面几种方式来优化循环
减值迭代
大多数循环使用一个从0开始、增加到某个特定值的迭代器,在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效
简化终止条件