一个简单的demo,从各个CDN上引用了2个CSS3个JS,在body里面创建了1000个li。通过调整外部引用资源的位置和加入相关的属性利用chrome的Timeline进行验证。
3.2 放置在<head>内
异步加载资源,但会阻塞<body>的渲染会出现白屏,按照顺序立即执行脚本
3.3 放置在<body>底部
异步加载资源,等<body>中的内容渲染完毕后且加载完按顺序执行JS
3.3 放置在<head>头部并使用async
异步加载资源,且加载完JS资源立即执行,并不会按顺序,谁快谁先上
3.4 放置在<head>头部并使用defer
异步加载资源,在DOM渲染后之后再按顺序执行JS
3.5 放置在<head>头部并同时使用async和defer
表现和async一致,开了个脑洞,把这两个属性交换一下位置,看会不会有覆盖效果,结果发现是一致的 = =、
综上,在webkit引擎下,建议的方式仍然是把<script>写在<body>底部,如果需要使用百度谷歌分析或者不蒜子等独立库时可以使用async属性,若你的<script>标签必须写在<head>头部内可以使用defer属性
四、 兼容性
那么,揣摩一下前辈的心理,同时写上的原因是什么呢,兼容性?
上caniuse,async在IE<=9时不支持,其他浏览器OK;defer在IE<=9时支持但会有bug,其他浏览器OK;现象在这个issue里有描述,这也就是“望远镜”里建议只有一个defer的原因。所以两个属性都指定是为了在async不支持的时候启用defer,但defer在某些情况下还是有bug。
The defer attribute may be specified even if the async attribute is specified, to cause legacy Web browsers that only support defer (and not async) to fall back to the defer behavior instead of the synchronous blocking behavior that is the default.
五、结论
其实这么讲来,最稳妥的办法还是把<script>写在<body>底部,没有兼容性问题,没有白屏问题,没有执行顺序问题,高枕无忧,不要搞什么defer和async的花啦~
目前只研究了chrome的webkit的渲染机制,Firefox和IE的有待继续研究,图片和CSS以及其他外部资源的渲染有待研究。