part2:数据访问和dom操作的优化
2016-08-10 22:14
169 查看
第二部分先说说数据访问中的优化问题。这部分是对作用域链,原型链这些访问数据的过程中需要沿着搜索的链的讲解,这个理解好,书中的内容就很容易理解。
访问数据时的性能问题发生在沿着作用域链或原型链找数据的过程中,就好像翻抽屉,如果要找的东西打开抽屉就能看见,很快就能找到。如果找不到,我们就会看看抽屉里有没有盒子之类的东西,然后在盒子里找。东西藏得越深,找起来就越麻烦。当在一个函数中访问某个数据,它首先会在函数定义的局部变量中找,然后在包含它的函数中找(若没有则在全局中找)。当然,沿着原型链访问也是类似的道理,越深层次的数据访问起来也就越慢。我们可以通过将经常访问的外部变量的值赋给一个局部变量来解决问题。
比如,当进行dom操作时,我们经常会使用document对象,可以这样进行简单的优化:
function xxx(){
var dom = document;
//dom操作
}
此外,访问对象成员的速度也比访问普通局部变量要慢的多,如果我们要多次使用某个对象成员的值,也可以用相同的方法为它保存一个“局部版本”。
提到作用域链了,那么就避不开闭包。关于闭包,我初学的时候很奇怪这东西到底干嘛的,解释是有权访问另一个函数作用域中的变量的函数就叫闭包,那不是所有函数中定义的函数都是闭包了吗,但这有啥用呢,不就是作用域链的效果吗。
直到后来,我发现闭包经常用来实现从“外面”访问“里面”的变量。比如:
(function (){
var i = 111;
var element = document.getElementById("someElement");
element.onclick = function(){
alert(i);
};
element = null;
})();
这样一来,我们就可以在外部访问内部的i变量,只要点击了element元素,就会弹出i的值。
闭包的缺点,就是外部函数的变量就一直保存在内存中了,除非通过手动解除引用来回收。比如上面的例子,当不需要访问i时,可以这样element.onclick = null;来回收内存,书上没这样写,我觉得应该是这样。。。
———————————————————————————————————————————————————
接着是dom操作方面的优化。这里出现两个词,重排版(reflow)和重绘(repaint)。这两者都是极其消耗性能的,所以dom操作的优化很大一部分就是如何减少重排版和重绘。另一部分则是关于如何“html集合”的。
我们经常会用document.getElement/sByxxx()这一类的方法,这类方法返回的是一个html集合,同样返回html集合的还有document.images,document.links,document.forms。这个html集合是动态的,也就是说,它的内容随着整个html文档的改变而改变。我们由此可以猜出,访问它也是极其消耗性能的。看如下的几个例子:
// slow
function collectionGlobal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = document.getElementsByTagName('div')[count].nodeName;
name = document.getElementsByTagName('div')[count].nodeType;
name = document.getElementsByTagName('div')[count].tagName;
}
return name;
};
// faster
function collectionLocal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = coll[count].nodeName;
name = coll[count].nodeType;
name = coll[count].tagName;
}
return name;
};
// fastest
function collectionNodesLocal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
el = null;
for (var count = 0; count < len; count++) {
el = coll[count];
name = el.nodeName;
name = el.nodeType;
name = el.tagName;
}
return name;
};
代码并不复杂,分别是实现相同功能的三个版本,性能上一个比一个好。
dom的部分有点多,剩下的下次再写。
访问数据时的性能问题发生在沿着作用域链或原型链找数据的过程中,就好像翻抽屉,如果要找的东西打开抽屉就能看见,很快就能找到。如果找不到,我们就会看看抽屉里有没有盒子之类的东西,然后在盒子里找。东西藏得越深,找起来就越麻烦。当在一个函数中访问某个数据,它首先会在函数定义的局部变量中找,然后在包含它的函数中找(若没有则在全局中找)。当然,沿着原型链访问也是类似的道理,越深层次的数据访问起来也就越慢。我们可以通过将经常访问的外部变量的值赋给一个局部变量来解决问题。
比如,当进行dom操作时,我们经常会使用document对象,可以这样进行简单的优化:
function xxx(){
var dom = document;
//dom操作
}
此外,访问对象成员的速度也比访问普通局部变量要慢的多,如果我们要多次使用某个对象成员的值,也可以用相同的方法为它保存一个“局部版本”。
提到作用域链了,那么就避不开闭包。关于闭包,我初学的时候很奇怪这东西到底干嘛的,解释是有权访问另一个函数作用域中的变量的函数就叫闭包,那不是所有函数中定义的函数都是闭包了吗,但这有啥用呢,不就是作用域链的效果吗。
直到后来,我发现闭包经常用来实现从“外面”访问“里面”的变量。比如:
(function (){
var i = 111;
var element = document.getElementById("someElement");
element.onclick = function(){
alert(i);
};
element = null;
})();
这样一来,我们就可以在外部访问内部的i变量,只要点击了element元素,就会弹出i的值。
闭包的缺点,就是外部函数的变量就一直保存在内存中了,除非通过手动解除引用来回收。比如上面的例子,当不需要访问i时,可以这样element.onclick = null;来回收内存,书上没这样写,我觉得应该是这样。。。
———————————————————————————————————————————————————
接着是dom操作方面的优化。这里出现两个词,重排版(reflow)和重绘(repaint)。这两者都是极其消耗性能的,所以dom操作的优化很大一部分就是如何减少重排版和重绘。另一部分则是关于如何“html集合”的。
我们经常会用document.getElement/sByxxx()这一类的方法,这类方法返回的是一个html集合,同样返回html集合的还有document.images,document.links,document.forms。这个html集合是动态的,也就是说,它的内容随着整个html文档的改变而改变。我们由此可以猜出,访问它也是极其消耗性能的。看如下的几个例子:
// slow
function collectionGlobal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = document.getElementsByTagName('div')[count].nodeName;
name = document.getElementsByTagName('div')[count].nodeType;
name = document.getElementsByTagName('div')[count].tagName;
}
return name;
};
// faster
function collectionLocal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = coll[count].nodeName;
name = coll[count].nodeType;
name = coll[count].tagName;
}
return name;
};
// fastest
function collectionNodesLocal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
el = null;
for (var count = 0; count < len; count++) {
el = coll[count];
name = el.nodeName;
name = el.nodeType;
name = el.tagName;
}
return name;
};
代码并不复杂,分别是实现相同功能的三个版本,性能上一个比一个好。
dom的部分有点多,剩下的下次再写。
相关文章推荐
- 深入理解PHP之匿名函数
- 最后一次说说闭包
- Ruby中使用Block、Proc、lambda实现闭包
- LUA中的闭包(closure)浅析
- Lua中的闭包学习笔记
- C#中函数的创建和闭包的理解
- 锋利的jQuery 要点归纳(二) jQuery中的DOM操作(下)
- 深入理解javascript作用域和闭包
- javascript作用域和闭包使用详解
- 谈谈JavaScript中的函数与闭包
- 细品javascript 寻址,闭包,对象模型和相关问题
- JavaScript中的闭包原理分析
- 浅谈javascript中的闭包
- 学习javascript的闭包,原型,和匿名函数之旅
- javascript 闭包详解
- JavaScript 匿名函数和闭包介绍
- JavaScript 闭包深入理解(closure)
- 深入理解JavaScript 闭包究竟是什么
- 让你一句话理解闭包(简单易懂)
- 谈谈我对JavaScript原型和闭包系列理解(随手笔记8)