Javascript性能优化(一)
一、加载
1. 依据HTML 4规范,script标签可以放置在head和body标签中的任意位置
2. 下载js脚本会阻塞其他页面文件下载,所以应尽可能将script标签放置在body底部
3. HTML 4为script标签增加了一个defer属性,表明延迟执行,但这并不是标准做法
4. 将多个script合并后压缩,放置在body标签底部,是引入多个外链javascript文件的最佳实践
5. 通过动态创建标签,可以异步引入js文件,代码如下:
1 function loadScript(url, callback) { 2 3 var script = document.createElement(‘script‘) 4 script.type = ‘text/javascript‘ 5 6 // IE 7 if (script.readyState) { 8 script.onreadystatechange = function() { 9 if (script.readyState == ‘loaded‘ || script.readyState == ‘complete‘) { 10 script.onreadystatechange = null 11 callback() 12 } 13 } 14 15 // other browser 16 } else { 17 script.onload = function() { 18 callback() 19 } 20 } 21 22 script.src = url 23 document.getElementByTagName(‘head‘)[0].appendChild(script) 24 }
6.使用xhr对象,同样可以异步引入js。与上面不同的是,你可以获得准确的加载进度,并且,脚本并不是一下载好就执行(取决于script标签添加到页面中的时间)
1 var xhr = new XMLHttpRequest() 2 3 xhr.open(‘get‘, ‘file.js‘, true) 4 xhr.onreadystatechange = function() { 5 6 if (xhr.readyState == 4) { 7 if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { 8 9 var script = document.createElement(‘script‘) 10 11 script.type = ‘text/javascript‘ 12 script.text = xhr.responseText 13 14 document.body.appendChild(script) 15 } 16 } 17 }
二、数据
1. javascript数据类型:直接量、变量、数组、对象
2. 直接量和局部变量的访问速度优于数组项和对象成员,变量访问性能与作用域嵌套有直接关系
3. 闭包比非闭包函数需要更多内存开销(变量的生命周期延长,并且最后不一定能释放)
4. 使用hasOwnProperty只对实例进行查找,而使用for in遍历对象成员可以访问prototype
5. 每次使用 "." 操作符时,会导致javascript引擎搜索所有对象成员,对象成员嵌套越深,速度越慢。尤其是当访问的属性(方法)在原型链中时
6. 使用 "." 操作符,在safari下会比[key]更快,但[key]的写法更通用(属性为保留字)
7. 命名空间是导致频繁访问嵌套属性的起因之一,对命名空间进行缓存,可以有效减少对象访问次数
1 // 对命名空间进行缓存 2 var load = ME.core.load 3 4 // 对resource.length进行缓存,避免每次遍历都访问resource 5 for (var i = 0, length = resource.length; i < length; i++) { 6 7 load.LoadResource(resource[i].url) 8 }
三、DOM
1. 文档对象模型(DOM)是一个语言无关的,用于操作XML和HTML文档的应用程序接口
2. DOM和ECMAScript是两个独立的功能,当他们通过接口相互访问,就会产生消耗。访问DOM元素要被收取“过桥费”,修改元素则更为昂贵,因为它会导致浏览器重新计算页面的几何变化
3. 使用dom方式生成html(body.appendChild)与使用innerHTML效率大致相同,在旧版本浏览器上innerHTML更胜一筹
4. 在大多数浏览器上,克隆节点(cloneNode)比生成节点(createElement)更有效率
5. HTML集合一直与文档保持着链接,每次访问时,都会重复执行查询的过程,哪怕只是获取集合里的元素个数。以下方法和属性会造成这种低效率情况
1 document.getElementsByName() 2 document.getElementsByClassName() 3 document.getElementsByTagName() 4 5 document.images 6 document.forms 7 document.links 8 document.forms[0].elements
6. 遍历元素子节点,ie下使用nextSibling比childNodes更快
1 // nextSibling 2 function testNextSibling() { 3 var el = document.getElementById(‘father‘), 4 ch = el.firstChild, 5 name = ‘‘ 6 7 do { 8 name = ch.nodeName 9 10 } while(ch = ch.nextSibling) 11 12 return name 13 } 14 15 // childNodes 16 function testChildNodes() { 17 var el = document.getElementById(‘father‘), 18 ch = el.childNodes, 19 len = ch.length, 20 name = ‘‘ 21 22 for (var i = 0; i < len; i++) { 23 name = ch[i].nodeName 24 } 25 26 return name 27 }
7. 使用原生的querySelector和querySelectorAll将比遍历获得更好的效率(ie8+)
8. 当DOM的变化影响了几何属性(盒模型),其他元素的几何属性和位置也会因此受到影响(normal flow)。浏览器会使渲染树种受到影响的部分失效,并重新构造渲染树。这个过程称为“重排”。完成重排后,浏览器会重新绘制受到影响的部分到屏幕中,这个过程称为“重绘”。以下情况会发生重排:
- 添加或删除可见的DOM元素
- 元素位置改变
- 元素盒模型改变(padding、margin、width、height、border)
- 内容改变,如文字或图片路径
- 页面渲染器初始化
- 浏览器窗口尺寸改变
有些改动会触发整个页面的重排,例如,当滚动条出现时
9. 重排会产生计算消耗,多数浏览器会通过队列化修改并批量执行来优化重排过程。获取布局信息的操作会导致列队刷新,比如以下方法:
- offsetTop,offsetLeft,offsetWidth,offsetHeight
- scrollTop,scrollLeft,scrollWidth,scrollHeight
- clientTop,clientLeft,clientWidth,clientHeight
- getComputedStyle()
在修改样式的过程中最好避免使用上述属性
10. 将多次改动合并为一次,可以大幅提高效率。另一种一次性修改样式的方式是修改class属性,这种方法更利于维护和复用,虽然可能带来轻微性能影响(改变类时需要检查级联样式)
11. 有三个方法可以使DOM脱离文档流
- 隐藏元素,应用修改,重新显示
- 使用文档片段,在当前DOM树外构建一个子树,再拷贝回文档
- 将原始元素拷贝到一个脱离文档的节点中,修改副本,再替换原始元素
12. 在IE 7-8上大范围使用hover会降低响应速度
13. 通过事件委托可以减少事件的绑定数量,从而提升效率。通过子元素冒泡触发父元素的事件,可能更加简单和优雅
14. 将需要大量修改的DOM节点(动画元素)设置为绝对定位,使其脱离文档流以减少影响
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。