1.尽量少访问DOM和尽量减少标记
访问DOM的方式对脚本性能会产生非常大的影响。以下面代码为例:
if (document.getElementsByTagName("a").length > 0) {
var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++) {
//对每个链接做处理
}
}
这段代码可以运行,本身并没有什么问题,但它却不是我们期望的最优性能。细看这段代码,可以发现其先后两次使用DOM方法getElementsByTagName()来查询a元素,实际上相当于浪费了一次搜索。不管什么时候,只要是查询DOM中的某些元素,浏览器都会搜索整个DOM树,从中查找可能匹配的元素。所以这段代码对性能的影响,可见一斑。基于此,可以设计出更好的方案,即将第一次搜索的结果保存在变量中进行重用。如下:
var links = document.getElementsByTagName("a");
if (links.length > 0) {
for (var i=0; i<links.length; i++) {
//对每个链接做处理
}
}
这样以来,代码的功能没有变,但搜索DOM的次数由两次降到了一次,性能得到了最优化。
另外,有时在程序中写了多个函数,可能某些函数的功能有类似相近之处,这时就应该考虑重构,把可以共用的结果保存在全局变量里,把功能相近类似的函数高度抽象化,尽可能地减少对DOM的访问。
还有一个需要注意的地方,就是要尽量减少文档中的标记数量。过多不必要的的元素只会增加DOM树的规模,进而增加遍历DOM树以查找特定元素的时间。
2.合并和放置脚本
包含脚本的最佳方式就是使用外部文件,因为外部文件与标记能清晰地分离开来,而且浏览器也能对网站中的多个页面重用缓存过的相同脚本。不过,类似下面这种情况,最好也不要出现:
<script src="scripts/functionA.js"></script>
<script src="scripts/functionB.js"></script>
<script src="scripts/functionC.js"></script>
<script src="scripts/functionD.js"></script>
推荐的做法是把functionA.js functionB.js functionC.js functionD.js 合并到一个脚本文件中。这样,就可以减少加载页面时发送的请求数量。而减少请求数量通常都是在性能优化时首先要考虑的。
脚本在标记中的位置对页面的初次加载时间也有很大影响。传统上,我们都把脚本放在文档的head区域,这种放置方法有一个问题。位于head块中的脚本会导致浏览器无法并行加载其他文件(如图像或其他脚本)。一般来说,根据HTTP规范,浏览器每次从同一个域名中最多只能同时下载两个文件。而在脚本下载期间,浏览器不会下载其他任何文件,即使是来自不同域名的文件也不会下载,所有其他资源都要等脚本加载完毕后才能下载。
通过以上分析,可知:若位于head区域的脚本文件没有加载完毕,浏览器也不会加载body区域的html元素,这样一来,倘若脚本文件过大,用户要看到页面就需要等待很长时间,这当然不是我们所期望的。所以,在实际的web页面开发中,为了最快地把HTML页面呈现给用户,必须把所有script标签(注意:这里的所有,指的仅是对当前HTML页面进行操纵的脚本文件,某些另外引用的第三方库文件还是需要放在head区域以便在操纵页面的脚本之前加载)都放到文档的末尾,body标记之前。这样就可以让页面变得更快,先显示最基本的html页面,然后加载对页面进行操纵的脚本文件。即使这样,在加载脚本时,window对象的load事件依然可以执行对文档进行的各种操作。
这里举个例子,下面这张图片是我个人CSDN博客主页源代码末尾部分的截图,大家可以看到,这些脚本都是放在了文档末尾的body标记之前。有兴趣的的也可以右键查看源代码,会发现在head区域依然有script标签包含的脚本文件,这里面不仅有引用的第三方库文件,也有代码编写者自己设定的一些东西等需要在操纵页面的脚本之前加载。
3.压缩脚本
在写完了脚本,做了优化之后,而且也将它放到文档中的适当位置之后,还有一件事可以加快加载速度:压缩脚本文件。
所谓压缩脚本文件,指的是把脚本文件中不必要的字节,如空格和注释,统统删除,从而达到“压缩”文件的目的。好在,有很多工具都可以替我们来做这件事。有的精简程序甚至会重写部分代码,使用更短的变量名,从而减少整体文件的大小。
例子,下面这幅图片是Googles首页源代码部分截图,从图中,我们可以看到,脚本代码是经过精简的。
精简后的代码虽然不容易看懂,却能大幅度减少文件大小。多少情况下,我们应该有两个版本,一个是工作副本,可以修改源代码并添加注释;另一个是精简副本,用于放在站点上。通常,为了与非精简版区分开来,建议精简副本地文件名中加上min字样。如下:
<script src="scripts/scriptName.min.js"></script> //用于实际站点的精简版
<script src="scripts/scriptName.js"></script> //作为工作副本的正常版
下面推荐几个有代表性的代码压缩工具:
雅虎的YUI Compressor
谷歌的Closure Compiler