zoukankan      html  css  js  c++  java
  • javascript之DOM优化

    DOM访问和操作是现代网页应用中很重要的一部分。但每次你通过“桥梁”从ECMAScript到DOM时,都会被收取“过路费”。为减少DOM编程中的性能损失,具体要注意的有:

    一。最小化DOM访问,在javascript端做尽可能多的事。

    Js代码  收藏代码
    1. function innerHTMLLoop() {  
    2. for (var count = 0; count < 15000; count++) {  
    3. document.getElementById('here').innerHTML += 'a';  
    4. }  
    5. }  
    6. function innerHTMLLoop2() {  
    7. var content = '';  
    8. for (var count = 0; count < 15000; count++) {  
    9. content += 'a';  
    10. }  
    11. document.getElementById('here').innerHTML += content;  
    12. }  

     innerHTMLLoop2显然要比innerHTMLLoop更好。

    二。在反复访问的地方使用局部变量存放DOM引用。

    (此点结合第三点一起)

    三。小心地处理HTML集合,因为他们表现出“存在性”,总是对底层文档重新查询。将集合length属性缓存到一个变量中,在迭代中使用这个变。如果经常操作这个集合,可以将集体拷贝到数组中。

    Js代码  收藏代码
    1. HTML集合有:  
    2. document.getElementsByName()  
    3. document.getElementsByClassName()  
    4. document.getElementsByTagName_r()  
    5. document.images  
    6. document.links  
    7. document.forms  
    8. document.forms[0].elements  

    这些方法和属性返回HTMLCollection 对象,是一种类似数组的列表。它们不是数组(因为它们没有诸

    如push()或slice()之类的方法),但是提供了一个length 属性,和数组一样你可以使用索引访问列表中的

    元素。例如,document.images[1]返回集合中的第二个元素。正如DOM 标准中所定义的那样,HTML 集合

    是一个“虚拟存在,意味着当底层文档更新时,

    Js代码  收藏代码
    1. var alldivs = document.getElementsByTagName_r('div');  
    2. for (var i = 0; i < alldivs.length; i++) {  
    3. document.body.appendChild(document.createElement('div'))  
    4. }  
    5. 这段代码看上去只是简单地倍增了页面中div 元素的数量。它遍历现有div,每次创建一个新的div 并附  
    6. 加到body 上面。但实际上这是个死循环,因为循环终止条件alldivs.length 在每次迭代中都会增加,它反  
    7. 映出底层文档的当前状态。  

    将一个HTML集合拷贝给一个数组:

    Js代码  收藏代码
    1. function toArray(coll) {  
    2. for (var i = 0, a = [], len = coll.length; i < len; i++) {  
    3. a[i] = coll[i];  
    4. }  
    5. return a;  
    6. }  
    Js代码  收藏代码
    1. var coll = document.getElementsByTagName_r('div');  
    2. var ar = toArray(coll);  
    3. //slower  
    4. function loopCollection() {  
    5. for (var count = 0; count < coll.length; count++) {  
    6. }  
    7. }  
    8. // faster  
    9. function loopCopiedArray() {  
    10. for (var count = 0; count < arr.length; count++) {  
    11. }  
    12. }  
    13. // faster  
    14. function loopCacheLengthCollection() {  
    15. var coll = document.getElementsByTagName_r('div'),  
    16. len = coll.length;  
    17. for (var count = 0; count < len; count++) {  
    18. }  
    19. }  

    一般来说,对于任何类型的DOM 访问,如果同一个DOM 属性或方法被访问一次以上,最好使用一个

    局部变量缓存此DOM 成员。当遍历一个集合时,第一个优化是将集合引用存储于局部变量,并在循环之

    外缓存length 属性。然后,如果在循环体中多次访问同一个集合元素,那么使用局部变量缓存它。

    Js代码  收藏代码
    1. // slow  
    2. function collectionGlobal() {  
    3. var coll = document.getElementsByTagName_r('div'),  
    4. len = coll.length,  
    5. name = '';  
    6. for (var count = 0; count < len; count++) {  
    7. name = document.getElementsByTagName_r('div')[count].nodeName;  
    8. name = document.getElementsByTagName_r('div')[count].nodeType;  
    9. name = document.getElementsByTagName_r('div')[count].tagName;  
    10. }  
    11. return name;  
    12. };  
    13. // faster  
    14. function collectionLocal() {  
    15. var coll = document.getElementsByTagName_r('div'),  
    16. len = coll.length,  
    17. name = '';  
    18. for (var count = 0; count < len; count++) {  
    19. name = coll[count].nodeName;  
    20. name = coll[count].nodeType;  
    21. name = coll[count].tagName;  
    22. }  
    23. return name;  
    24. // fastest  
    25. function collectionNodesLocal() {  
    26. var coll = document.getElementsByTagName_r('div'),  
    27. len = coll.length,  
    28. name = '',  
    29. el = null;  
    30. for (var count = 0; count < len; count++) {  
    31. el = coll[count];  
    32. name = el.nodeName;  
    33. name = el.nodeType;  
    34. name = el.tagName;  
    35. }  
    36. return name;  
    37. };  

    四。可能的话,使用速度更快的API,诸如querySelectorAll()和firstElementChild

    下列浏览器支持选择器API:Internet Explorer 8,Firefox 3.5,Safari 3.1,Chrome 1,Opera 10。

    具体用法此处不详解。

    五。注重重绘和重排版:批量修改风格,离线操作DOM树,缓存并减少对布局信息的访问。

    当浏览器下载完所有页面HTML 标记,JavaScript,CSS,图片之后,它解析文件并创建两个内部数据

    结构:一棵DOM树(表示页面结构),一棵渲染树(表示DOM节点如何显示)。

    重排版的情况:

    添加或删除可见的DOM元素

    元素位置改变

    元素尺寸改变(因为边距,填充,边框宽度,宽度,高度等属性改变)

    内容改变,例如文本改变或图片被另一个不同尺寸的所替代

    最初的页面渲染

    浏览器窗口改变尺寸

    (1)批量修改

    重排版和重绘代价昂贵,所以,提高程序响应速度一个好策略是减少此类操作发生的机会。为减少发生

    次数,你应该将多个DOM 和风格改变合并到一个批次中一次性执行。

    Js代码  收藏代码
    1. var el = document.getElementById('mydiv');  
    2. el.style.borderLeft = '1px';  
    3. el.style.borderRight = '2px';  
    4. el.style.padding = '5px';  
    5.   
    6. //better  
    7. var el = document.getElementById('mydiv');  
    8. el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';  
    9.   
    10. 如果你打算保持当前的风格,你可以将它附加在cssText 字符串的后面。  
    11. el.style.cssText += '; border-left: 1px;';  
    12.   
    13. //or  
    14. var el = document.getElementById('mydiv');  
    15. el.className = 'active';  

    (2)离线操作DOM

    Js代码  收藏代码
    1. var data = [  
    2. {  
    3. "name": "Nicholas",  
    4. "url": "http://nczonline.net"  
    5. },  
    6. {  
    7. "name": "Ross",  
    8. "url": "http://techfoolery.com"  
    9. }  
    10. ];  
    11. //一个通用的函数,用于将新数据更新到指定节点中  
    12. function appendDataToElement(appendToElement, data) {  
    13. var a, li;  
    14. for (var i = 0, max = data.length; i < max; i++) {  
    15. a = document.createElement('a');  
    16. a.href = data[i].url;  
    17. a.appendChild(document.createTextNode(data[i].name));  
    18. li = document.createElement('li');  
    19. li.appendChild(a);  
    20. appendToElement.appendChild(li);  
    21. }  
    22. };  
    23.   
    24. <strong>//减少重排版的一个方法是通过改变display 属性,临时从文档上移除<ul>元素然后再恢复它。</strong>  
    25. var ul = document.getElementById('mylist');  
    26. ul.style.display = 'none';  
    27. appendDataToElement(ul, data);  
    28. ul.style.display = 'block';  
    29.   
    30. <strong>//在文档之外创建并更新一个文档片断,然后将它附加在原始列表上。  
    31. 文档片断是一个轻量级的document 对象,它被设计专用于更新、移动节点之类的任务</strong>  
    32. var fragment = document.createDocumentFragment();  
    33. appendDataToElement(fragment, data);  
    34. document.getElementById('mylist').appendChild(fragment);  
    35.   
    36. <strong>//创建要更新节点的副本,然后在副本上操作,最后用新节点覆盖老节点</strong>  
    37. var old = document.getElementById('mylist');  
    38. var clone = old.cloneNode(true);  
    39. appendDataToElement(clone, data);  
    40. old.parentNode.replaceChild(clone, old);  

    推荐尽可能使用文档片断(第二种解决方案)因为它涉及最少数量的DOM 操作和重排版。唯一潜在的

    缺点是,当前文档片断还没有得到充分利用,开发者可能不熟悉此技术。

    (3)缓存布局信息

    尽量减少对布局信息的查询次数,查询时将它赋给局部变量,并用局部变量参与计算。

    Js代码  收藏代码
    1. //timeout中的代码  
    2. myElement.style.left = 1 + myElement.offsetLeft + 'px';  
    3. myElement.style.top = 1 + myElement.offsetTop + 'px';  
    4. if (myElement.offsetLeft >= 500) {  
    5. stopAnimation();  
    6. }  
    7.   
    8. //优化后  
    9. current++  
    10. myElement.style.left = current + 'px';  
    11. myElement.style.top = current + 'px';  
    12. if (current >= 500) {  
    13. stopAnimation();  
    14. }  

    六。动画中使用绝对坐标,使用拖放代理。

    七。使用事件托管技术最小化事件句柄数量。

    当页面中存在大量元素,而且每个元素有一个或多个事件句柄与之挂接(例如onclick)时,可能会影

    响性能。连接每个句柄都是有代价的,无论其形式是加重了页面负担(更多的页面标记和JavaScript 代码)

    还是表现在运行期的运行时间上。你需要访问和修改更多的DOM 节点,程序就会更慢,特别是因为事件

    挂接过程都发生在onload(或DOMContentReady)事件中,对任何一个富交互网页来说那都是一个繁忙的

    时间段。挂接事件占用了处理时间,另外,浏览器需要保存每个句柄的记录,占用更多内存。当这些工作

    结束时,这些事件句柄中的相当一部分根本不需要(因为并不是100%的按钮或者链接都会被用户点到),

    所以很多工作都是不必要的。

  • 相关阅读:
    HDFS Maintenance State
    HDFS Maintenance State
    HDFS“慢节点”监控分析功能
    Confluence 6 找到你的支持识别代码(SEN)
    Confluence 6 降级你的许可证
    Confluence 6 增加和减少你许可证的用户数
    Confluence 6 理解你许可证的用户数
    Confluence 6 升级你的许可证
    Confluence 6 查看你的许可证细节
    Confluence 6 管理你的 Confluence 许可证
  • 原文地址:https://www.cnblogs.com/hr2014/p/3861379.html
Copyright © 2011-2022 走看看