今天读到Steve Souders的一篇关于如何放置内联脚本的文章-Positioning Inline Scripts,现总结在文本。
之前译的一篇文章《无阻塞加载脚本》谈到的是外部脚本对于页面性能的影响,例如阻塞资源下载、阻塞页面渲染等。而对于inline的脚本,同样存在类似的问题,有的甚至是有过之而无不及。
一、阻塞页面渲染
外链脚本对于页面的渲染阻塞效果仅仅局限于脚本后面的内容,而对于inline脚本而言则是整个页面,而且不论你把脚本放置在什么位置(即使是body之后)均会阻塞整个页面的渲染,可以点击这里查 看。在该例子中,在head里引用了一个外部脚本和样式表,而在页面的最后添加了一段inline脚本,脚本的作用是等待2秒钟。打开页面的最初几秒时间 内,你将看不到任何内容,直到最后的内联脚本执行完毕页面才渲染出来。即使改变inline脚本的位置,渲染依旧要等到脚本执行完毕才能进行,也就是说, 无论inline脚本放在什么地方都会阻塞整个页面的渲染!
时间瀑布图
从图中可以看出,当脚本位于资源之后时,并未阻塞资源的下载。
二、阻塞资源下载
修改一下上个例子中的脚本位置,将脚本从body之后挪到外部脚本之前,点击这里查看。从下图中可以清晰的看到,在页面加载完成后到开始下载资源之间有大概2s左右的间隔时间,这个时间恰好是inline脚本执行的时间,这充分表明了inline脚本对资源的阻塞作用。
时间瀑布图
三、解决方案
既然inline脚本如此可怕,那如何解决这个问题呢,文中主要提到了以下三点建议:
- 将inline脚本移到页面最底部,也就是上面第一个例子中的做法,该方法虽然必能不能避免阻塞页面的渲染,但至少不会影响资源的下载。而从第一 个例子的时间瀑布图中可以非常明显的看出,脚本和样式的下载是在页面加载完成后立即执行的,并没有受inline脚本的影响,反过来,从第二个例子的时间 图则可以清晰的看出inline脚本的执行阻塞了资源的下载,因此将inline脚本尽可能的后移对于资源下载来说确实是有好处的。
- 对于执行时间较长的代码可以考虑使用setTimeout来执行,使用这种方法不仅可以解决资源下载阻塞问题,还可以解决执行脚本对页面渲染的阻塞问题。
- 对于IE或Firefox3.1及以上版本中的脚本使用defer属性。
以下分别测试下第二和第三种解决方式。
setTimeout
时间瀑布图
与例2相比,在该例子中,给等待代码加了个setTimeout,效果可以从上图中看出。inline脚本的长时间执行并未阻塞资源的下载和页面的渲染,效果非常好。
defer
时间瀑布图
从上面的时间图中可以看出,给inline脚本添加defer属性后,长时间执行的脚本并未阻塞资源的下载。而从实际的页面效果来看,使用defer并没有改变脚本长时间执行对页面渲染的阻塞效果,页面的渲染依然要等到脚本执行完毕后才能完成。
以上三种方式在解决资源阻塞方面的效果都差不多,能够解决的比较好。而在页面渲染方面,个人觉得效果从大到小应该是setTimeout > defer > bottom。setTimout对于脚本执行的时机能够比较灵活的把握,通过调整执行的时机可以获得比较理想的效果;defer依赖于浏览器的行为,可 控性差,假如延长的时间小于其他资源的下载时间仍然会阻塞页面的渲染(从实际效果看,貌似defer并没有解决渲染问题);将脚本放置在页面底部对于解决 渲染阻塞无影响。从兼容性考虑,setTimeout和bottom则是最好的,而defer仅适用于IE和FF3.1及以上版本。
此外,需要注意的是尽量不要将inline脚本放在外部样式后面,因为主流的浏览器为了确保执行顺序,都会在样式下载、解析以及应用完成后才会执行其后的脚本,因此,会造成更严重的阻塞,查看例子。
时间瀑布图
从图中可以看出,浏览器是在样式下载完毕后才开始执行脚本的,从而导致样式和外部脚本不能并行下载,所以即使是将inline脚本放在外部样式文件之前也不要放在后面。
四、总结
- inline脚本对页面性能可以有很大的影响,在使用的时候需要额外注意摆放的位置以及执行效率等。
- 尽量把inline脚步往后放,越后越好,这样可以最大程度避免脚本执行对于下载资源的影响,但是无法避免对于页面渲染的阻塞。
- 对于执行时间较长的脚本,可以考虑使用setTimeout将之脱离出来执行,该方式可以有效避免脚本执行而导致的资源下载阻塞以及页面渲染阻塞。
- 此外,对于长时间执行的脚步也可以使用defer,但是兼容性以及灵活性不如setTimeout。
5 Comments »
衣服自己洗 说:
07/16/2009 - 14:44
多谢,你讲的这些东西我并没有注意。thx
天堂左我往右 说:
09/16/2009 - 20:58
defer这个属性不错,不过兼容性还是不够啊,呵呵
老田 说:
03/15/2010 - 16:36
真是有缘,我的博客的页面风格、研究的内容,和你都差不多!
admin 说:
03/16/2010 - 13:36
呵呵,果然如此,多多交流!
supersha 说:
06/14/2010 - 03:26
不错不错!!
经过本人的测试也总结了几点:
第一,不要将行内脚本(即使就一个script标签),不要放置到link链接的外部脚本的后面(并不一定要是紧跟)和其他资源之间,这样会造成阻塞后续资源的加载。
第二,给script标签同时加上defer和async属性,使得支持defer和async的浏览器(chrome,FF等较新版本都支持)可以延迟和异步加载、执行代码。