一.避免行内脚本阻塞渲染
把行内脚本移至底部(
body
结束标签前)使用异步回调启动JavaScript的执行
使用script的defer属性
把行内脚本移至底部
把行内脚本放在body
的结束标签前
优点:简单易用,页面内的图片等资源和位于底部的行内脚本并行下载
缺点:仍然会阻塞页面渲染,如果行内脚本执行时间很长(大于300ms),就不应该用这种简单方法了
异步启动执行脚本
通过setTimeout(doStuff, 0)
来异步执行脚本,在Firefox中需要延迟250ms(250是Nglayout.initialpaint.delay)
优点:可以实现逐步渲染,在行内脚本开始执行之前,浏览器会先渲染DOM内容(多半是文字)
缺点:会阻塞图片的渲染,如果图片响应返回时正在doStuff
,图片将等到doStuff
结束才会显示。此时应该放弃setTimeout
,改用window.onload
启动脚本执行。当然,如果行内脚本执行时间很短(小于300ms),用setTimeout
是没问题的
P.S.对于执行时间很长的行内脚本,最理想的方案是每隔300ms分块执行,setTimeout(doChunk, 300)
,但需要大规模重构代码,把大块逻辑分成一些小片段(300ms内能够完成的)
使用script的defer属性
defer
属性也适用于行内脚本,允许浏览器继续解析和渲染页面的同时延迟执行行内脚本
优点:资源并行下载
缺点:阻塞渲染,只适用于执行时间较短的行内脚本,很长的脚本仍然需要setTimeout
二.样式表也会阻塞行内脚本
除了按引入顺序执行js,浏览器还会保证按引入顺序解析css(因为不同的解析顺序会导致不同的样式结果,比如同优先级样式覆盖规则)
鲜为人知的:浏览器还会保持css和js的解析顺序,如果把行内脚本放在样式表之后,会明显地延迟资源的下载(结果是样式表下载完成并且行内脚本执行完毕时,后续资源才能开始下载)
这是因为行内脚本可能含有依赖于样式表中样式的代码,比如document.getElementsByClassName()
结论:在样式表后面的行内脚本会阻塞所有后续资源的下载(或者说,如果样式表后面没有行内脚本的话,样式表将与其它资源并行下载。当然,无论行内脚本前面有没有样式表,行内脚本都会阻塞后续资源的下载)
三.总结
行内脚本可能会导致css变成阻塞的,保证只引用外部脚本就可以避免这个问题
参考资料
- 《高性能网站建设进阶指南》