变量查找优化

慎用全局变量

1. 全局变量需要搜索更长的作用域链。

2. 全局变量的生命周期比局部变量长,不利于内存释放。

3. 过多的全局变量容易造成混淆,增大产生bug的可能性。

缓存重复使用的全局变量

1. 全局变量要比局部变量需要搜索的作用域长

2. 重复调用的方法也可以通过局部缓存来提速

3. 该项优化在IE上体现比较明显

核心语法优化

通过原型优化方法定义

1. 如果一个方法类型将被频繁构造,通过方法原型从外面定义附加方法,从而避免方法的重复定义。
2. 可以通过外 部原型的构造方式初始化值类型的变量定义。(这里强调值类型的原因是,引用类型如果在原型中定义, 一个实例对引用类型的更改会影响到其他实例。)

这条规则中涉及到JavaScript中原型的概念,

  • 构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。我们可 以把那些不变的属性和方法,直接定义在prototype对象上。

  • 可以通过对象实例访问保存在原型中的值,不能通过对象实例重写原型中的值。

  • 在实例中添加一个与实例原型同名属性,那该属性就会屏蔽原型中的属性。

  • 通过delete操作符可以删除实例中的属性。

避开闭包陷阱

1. 闭包是个强大的工具,但同时也是性能问题的主要诱因之一。不合理的使用闭包会导致内存泄漏。

2. 闭包的性能不如使用内部方法,更不如重用外部方法。

由于IE浏览器的DOM是用COM来实现的, COM的内存管理是通过引用计数的方式,引用计数有个难题就是循环引用,一旦DOM 引用了闭包(例如event handler),闭包的上层元素又引用了这个DOM,就会造成循环引用从而导致内存泄漏。

避免使用属性访问方法

1. JavaScript不需要属性访问方法,因为所有的属性都是外部可见的。
2. 添加属性访问方法只是增加了一层重定向 ,对于访问控制没有意义。

避免在循环中使用try-catch

1. try-catch-finally语句在catch语句被执行的过程中会动态构造变量插入到当前域中,对性能有一定影响。
2. 如 果需要异常处理机制,可以将其放在循环外层使用。

使用for代替for…in…遍历数组

for…in…内部实现是构造一个所有元素的列表,包括array继承的属性,然后再开始循环。相对for循环性能要慢。

使用原始操作代替方法调用

方法调用一般封装了原始操作,在性能要求高的逻辑中,可以使用原始操作代替方法调用来提高性能。

原始操作

1
var min = a < b ? a : b;

方法实例

1
var min = Math.min(a, b);

传递方法取代方法字符串

一些方法例如setTimeout()/setInterval(),接受字符串或者方法实例作为参数。直接传递方法对象作为参数来避免对字 符串的二次解析。

传递方法

1
setTimeout(test, 1);

传递方法字符串

1
setTimeout('test()', 1);
脚本装载优化

设置Cache-Control和Expires头

通过Cache-Control和Expires头可以将脚本文件缓存在客户端或者代理服务器上,可以减少脚本下载的时间。

异步加载脚本

脚本加载与解析会阻塞HTML渲染,可以通过异步加载方式来避免渲染阻塞。

异步加载的方式很多,比较通用的方法是通过类似下面的代码实现,

DOM操作优化

减少DOM元素数量

1. 在console中执行命令查看DOM元素数量

1
document.getElementsByTagName('*').length

2. Yahoo首页DOM元素数量在1200左右。正常页面大小一般不应该超过 1000。
3. DOM元素过多会使DOM元素查询效率,样式表匹配效率降低,是页面性能最主要的瓶颈之一。

优化CSS样式转换

如果需要动态更改CSS样式,尽量采用触发reflow次数较少的方式。

例如以下代码逐条更改元素的几何属性,理论上会触发多次reflow

1
2
3
element.style.fontWeight = 'bold';
element.style.marginLeft= '30px';
element.style.marginRight = '30px';

可以通过直接设置元素的className直接设置,只会触发一次reflow

     element.className = 'selectedAnchor';

优化节点添加、修改

1、多个节点插入操作,即使在外面设置节点的元素和风格再插入,由于多个节点还是会引发多次reflow。优化的方法是创建 DocumentFragment,在其中插入节点后再添加到页面。

2、对于节点的修改,可以考虑使用cloneNode在外部更新节点然后再通过replace与原始节点互换。

避免遍历大量元素

避免对全局DOM元素进行遍历,如果parent已知可以指定parent在特定范围查询。

事件优化

使用事件代理

1. 当存在多个元素需要注册事件时,在每个元素上绑定事件本身就会对性能有一定损耗。
2. 由于DOM Level2事件模 型中所有事件默认会传播到上层文档对象,可以借助这个机制在上层元素注册一个统一事件对不同子元素进行相应处理。

捕获型事件先发生。两种事件流会触发DOM中的所有对象,从document对象开始,也在document对象结束。

动画优化

动画效果在缺少硬件加速支持的情况下反应缓慢,例如手机客户端

特效应该只在确实能改善用户体验时才使用,而不应用于炫耀或者弥补功能与可用性上的缺陷

至少要给用户一个选择可以禁用动画效果

设置动画元素为absolute或fixed

position: static 或position: relative元素应用动画效果会造成频繁的reflow

position: absolute或position: fixed 的元素应用动画效果只需要repaint

使用一个timer完成多个元素动画

setInterval和setTimeout是两个常用的实现动画的接口,用以间隔更新元素的风格与布局。

动画效果的帧率最优化的情况是使用一个timer完成多个对象的动画效果,其原因在于多个timer的调用本身就会损耗一定 性能。

使用同一个timer,

setInterval(function() {
 animateFirst('');
 animateSecond('');
}, 10);