提高JavaScript加载速度的思考
JavaScript加载很多时候能够决定用户从打开页面看到页面的时间,JavaScript的加载与样式表和DOM以及图片等资源的加载既有相 同之处,又有很大的不同之处。最大的不同就是JavaScript的加载完成后会立即执行并阻塞页面的渲染,这就让脚本的加载与其他资源的加载有了很大的 不同。
在页面中直接引用的JavaScript会阻塞整个页面的加载,这就意味着每加载一个script标签就会有两种副作用:
1. 多占用一个Http的请求资源;
2. 加载完成后阻塞页面,直到JavaScript执行完毕。
HTTP/1.1的标准建议浏览器对同一个主机名只能并行下载不超过2个文件(事实上现在的浏览器的限制的数目都超过2个),这就意味着你引用的文件越多页面加载的速度将会变得越慢,因为很多文件都处于等待下载的状态中。要解决HTTP请求这个问题可以从两个方面着手:
1. 从多个主机名加载资源,这个可以使用多个二级域名的办法来实现,但是增加的引用文件的混乱程度;
2. 减少引用的资源数目。
具体到JavaScript的载入,当前比较常用的方法是使用压缩工具将多个JavaScript合并成一个文件,同时也能减小 JavaScript文件的体积。另外一个是通过统一的接口加载Script资源,后台程序将请求的文件合并成一个文件输出,并按照版本号进行缓存,后台 判断如果有缓存的版本且缓存未过期将直接输出缓存文件。后一种方法在wordpress中有类似的使用,但是未见wordpress进行文件的缓存,我曾 经写过一个类似的实现,将在后续的文章中放出。但是这个方法也有一个问题,因为要对文件进行合并,读写操作,另外考虑到后台语言的运行效率,所以对服务器 也将增加不少压力。
至于JavaScript加载过程中会阻塞页面,这个问题可以通过把JavaScript放到页面代码的最底部进行加载,这样会在页面显示完成之后 在执行JavaScript。当然script标签有个defer属性,可以让script标签在页面DOM加载完成之后执行,但是由于浏览器的支持程度 不同,所以使用defer属性不是一个稳妥的解决方案。
事实上当前还有一种比较流行的解决方案,就是使用JavaScript动态生成script节点,然后将其插入到文档中。动态的生成script节点插入文档的加载方式可以实现无阻塞的加载脚本资源,提高了下载的效率。通过两幅图对比一下:
图1:静态引入script标签时页面加载的时间条
图2:动态引入script标签时页面加载的时间条
图3:使用后台程序(PHP)合并之后输出
通过一次的测试并不能证明载入速度的快慢,所以载入时间在这里是无意义的。但是,通过查看载入的方式可以了解到,动态加载脚本的模式下,脚本的加载未阻塞图片的加载,而传统的方式则会在脚本加载完成之后再加载下面的内容。
动态载入script节点能够解决并行下载的问题,但是并无法解决JavaScript执行阻塞的问题,上面两图时间线中土黄色部分即为脚本执行的 阻塞时间,可以看到阻塞的时间甚至比加载的时间要长。上面提到了,解决这个问题的办法是把JavaScript放到文档的结尾处。如果使用script标 签动态加载的话这里就很方便,可以在DOM Ready或者Page onload的时候加载脚本,或者按需加载即什么时候用到什么时候加载,这样就不会阻塞页面的渲染。当然这个加载的时机还是要慎重考虑,根据脚本的作用进 行不同的调整。