DOM与JS就像两座独立的孤岛,中间有一座收费桥,JS每次操作DOM都需要过桥并被收取过桥费,所以要想优化DOM,就必须减少DOM操作。
var box = document.getElementById('box');
console.time('hello');
for(var i=0;i<5000;i++){
box.innerHTML += 'a';
}
console.time('hello'); //608ms
var box = document.getElementById('box');
var str = ''
console.time('hello');
for(var i=0;i<5000;i++){
str += 'a';
}
box.innerHTML = str; //1ms
console.time('hello');
innerHTML与dom方法对比:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oUl.appendChild(oLi);
}
console.timeEnd('hello');
var oUl = document.getElementById('oUl');
var str = '';
console.time('hello');
for(var i=0;i<5000;i++){
str += '<li></li>';
}
oUl.innerHTML = str;
console.timeEnd('hello');
结论:
chrome: innerHTML 与 dom方法性能差不多(不同的浏览器结论可能不一样)
firefox: innerHTML 要比dom方法性能好
DOM优化
减少DOM操作:
1. 节点克隆
--cloneNode
2. 访问元素集合
--尽量用局部变量
3. 元素节点
--尽量用只获取元素的节点方法
4. 选择器API
--利用querySelector, querySelectorAll
例1:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //29ms
//克隆节点
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
console.time('hello');
for(var i=0;i<5000;i++){
var newLi = oLi.cloneNode(true);
oUl.appendChild(newLi);
}
console.timeEnd('hello'); //7ms
例2:
var oUl = document.getElementById('oUl');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oUl.appendChild(oLi);
}
var oLi = oUl.getElementsByTagName('li');
console.time('hello');
for(var i=0;i<oLi.length;i++){
oLi[i].innerHTML = 'li';
}
console.timeEnd('hello'); //444ms
//用局部变量
var oLi = oUl.getElementsByTagName('li');
var len = oLi.length;
console.time('hello');
for(var i=0;i<len;i++){
oLi[i].innerHTML = 'li';
}
console.timeEnd('hello'); //439ms
例3:
var div = document.getElementById('box');
var input = document.getElementById('input');
var oUl = document.getElementById('ul');
//用局部变量
var doc = document;
var div = doc.getElementById('box');
var input = doc.getElementById('input');
var oUl = doc.getElementById('ul');
例子:
childNodes ----> 元素节点,文本节点
children ----> 元素节点
firstChild
firstElementChild
例4:
var oUl = document.getElementById('oUl');
var oLi = oUl.getElementsByTagName('li');
//相当于
var li = document.querySelectorAll('#oUl li');
DOM与浏览器
1. 重排:改变页面的内容
2. 重绘:浏览器显示内容
3. 添加顺序
--尽量在appendChild前添加操作
4. 合并dom操作
--利用cssText
5. 缓存布局信息
6. 文档碎片
--createDocumentFragment()
例1:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oUl.appendChild(oLi);
oLi.innerHTML = 'li';
}
console.timeEnd('hello'); //40ms
//在appendChild前添加操作
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //35ms
例2:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.style.width = '100px';
oLi.style.height = '100px';
oLi.style.background = 'red';
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //92ms
//利用cssText
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.style.cssText = "width:100px;height:100px;background:red";
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //69ms
例3:
var box = document.getElementById('box');
setInterval(function(){
box.style.left = box.offsetLeft + 1 +'px';
box.style.top = box.offsetTop + 1 +'px';
},30)
//缓存布局信息
var box = document.getElementById('box');
var L = box.offsetLeft;
var H = box.offsetTop;
setInterval(function(){
L++;
H++;
box.style.left = L +'px';
box.style.top = H +'px';
},30)
例4:
var oUl = document.getElementById('oUl');
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
console.time('hello');
for(var i=0;i<5000;i++){
var newLi = oLi.cloneNode(true);
oUl.appendChild(newLi);
}
console.timeEnd('hello'); //13ms
//利用文档碎片
var oUl = document.getElementById('oUl');
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
console.time('fragment');
var oFrag = document.createDocumentFragment();
for(var i=0;i<5000;i++){
var newLi = oLi.cloneNode(true);
oFrag.appendChild(newLi);
}
oUl.appendChild(oFrag);
console.timeEnd('fragment'); //9.74ms
DOM与事件
--事件委托
DOM与前端模板
var box = document.getElementById('box');
console.time('hello');
for(var i=0;i<5000;i++){
box.innerHTML += 'a';
}
console.time('hello'); //608ms
var box = document.getElementById('box');
var str = ''
console.time('hello');
for(var i=0;i<5000;i++){
str += 'a';
}
box.innerHTML = str; //1ms
console.time('hello');
innerHTML与dom方法对比:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oUl.appendChild(oLi);
}
console.timeEnd('hello');
var oUl = document.getElementById('oUl');
var str = '';
console.time('hello');
for(var i=0;i<5000;i++){
str += '<li></li>';
}
oUl.innerHTML = str;
console.timeEnd('hello');
结论:
chrome: innerHTML 与 dom方法性能差不多(不同的浏览器结论可能不一样)
firefox: innerHTML 要比dom方法性能好
DOM优化
减少DOM操作:
1. 节点克隆
--cloneNode
2. 访问元素集合
--尽量用局部变量
3. 元素节点
--尽量用只获取元素的节点方法
4. 选择器API
--利用querySelector, querySelectorAll
例1:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //29ms
//克隆节点
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
console.time('hello');
for(var i=0;i<5000;i++){
var newLi = oLi.cloneNode(true);
oUl.appendChild(newLi);
}
console.timeEnd('hello'); //7ms
例2:
var oUl = document.getElementById('oUl');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oUl.appendChild(oLi);
}
var oLi = oUl.getElementsByTagName('li');
console.time('hello');
for(var i=0;i<oLi.length;i++){
oLi[i].innerHTML = 'li';
}
console.timeEnd('hello'); //444ms
//用局部变量
var oLi = oUl.getElementsByTagName('li');
var len = oLi.length;
console.time('hello');
for(var i=0;i<len;i++){
oLi[i].innerHTML = 'li';
}
console.timeEnd('hello'); //439ms
例3:
var div = document.getElementById('box');
var input = document.getElementById('input');
var oUl = document.getElementById('ul');
//用局部变量
var doc = document;
var div = doc.getElementById('box');
var input = doc.getElementById('input');
var oUl = doc.getElementById('ul');
例子:
childNodes ----> 元素节点,文本节点
children ----> 元素节点
firstChild
firstElementChild
例4:
var oUl = document.getElementById('oUl');
var oLi = oUl.getElementsByTagName('li');
//相当于
var li = document.querySelectorAll('#oUl li');
DOM与浏览器
1. 重排:改变页面的内容
2. 重绘:浏览器显示内容
3. 添加顺序
--尽量在appendChild前添加操作
4. 合并dom操作
--利用cssText
5. 缓存布局信息
6. 文档碎片
--createDocumentFragment()
例1:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oUl.appendChild(oLi);
oLi.innerHTML = 'li';
}
console.timeEnd('hello'); //40ms
//在appendChild前添加操作
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //35ms
例2:
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.style.width = '100px';
oLi.style.height = '100px';
oLi.style.background = 'red';
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //92ms
//利用cssText
var oUl = document.getElementById('oUl');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi = document.createElement('li');
oLi.style.cssText = "width:100px;height:100px;background:red";
oUl.appendChild(oLi);
}
console.timeEnd('hello'); //69ms
例3:
var box = document.getElementById('box');
setInterval(function(){
box.style.left = box.offsetLeft + 1 +'px';
box.style.top = box.offsetTop + 1 +'px';
},30)
//缓存布局信息
var box = document.getElementById('box');
var L = box.offsetLeft;
var H = box.offsetTop;
setInterval(function(){
L++;
H++;
box.style.left = L +'px';
box.style.top = H +'px';
},30)
例4:
var oUl = document.getElementById('oUl');
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
console.time('hello');
for(var i=0;i<5000;i++){
var newLi = oLi.cloneNode(true);
oUl.appendChild(newLi);
}
console.timeEnd('hello'); //13ms
//利用文档碎片
var oUl = document.getElementById('oUl');
var oLi = document.createElement('li');
oLi.innerHTML = 'li';
console.time('fragment');
var oFrag = document.createDocumentFragment();
for(var i=0;i<5000;i++){
var newLi = oLi.cloneNode(true);
oFrag.appendChild(newLi);
}
oUl.appendChild(oFrag);
console.timeEnd('fragment'); //9.74ms
DOM与事件
--事件委托
DOM与前端模板
--能更好的对逻辑和视图分离,MVC框架的基础