3、探究CSS和JS阻塞问题( 五 )


事件:DOM树构建完毕就会触发,无需等待样式表、图像和子框架的完成加载 。
4、外部JS脚本的引用方式
defer属性
示例如下所示,defer是一个布尔属性,规定是否对外部JS脚本的执行进行延迟,直到页面上DOM解析完毕再执行外部脚本 。

每一个defer属性的脚本都会在页面解析完毕后,同时在的事件之前执行 。
async属性
示例如下所示,async是一个布尔属性,规定是否对外部JS脚本采用异步执行方式 。设置该属性后,则脚本相对于页面的其余部分异步执行(页面继续进行解析,同时脚本也将被执行) 。每一个async属性的脚本都在下载结束后立即执行,同时会在的load事件之前执行 。

注意,如果JS前后有依赖性,最好不要用async 。
注意,defer和async仅适用于外部脚本,只有在使用src属性时才有效,对内联脚本无效 。
标签不设置defer或async
若引用外部脚本时,既不使用async,也不使用defer,浏览器读取后,将立即执行,能够阻塞DOM解析 。
5、和link标签对DOM解析和渲染的影响
标签会阻塞DOM的解析
标签会阻塞DOM的解析,进而阻塞DOM的渲染 。如下代码所示,不论是内联还是外部脚本,只要位置在那里,打印结果都将为空
Documenthello word
标签会触发页面的Paint
标签或者说JS阻塞渲染,并不是页面不渲染,如果非要等到JS加载完毕在渲染,则等待时间太长 。实际上浏览器为了尽快让用户看到页面,在遇到标签时,会触发一次Paint,借此将标签之前的DOM元素渲染出来 。
但不是所有标签都会触发Paint 。head标签中的标签不会触发,毕竟此时body还没解析,根本没有内容来渲染 。其次内联的标签也不会触发Paint 。
因此,建议标签放在body结束标签之前,这样不会阻塞页面整体的内容的解析和渲染 。如果页面中只有内联的标签,那么放在任何位置,对页面的渲染影响是一样的 。
link标签不会阻塞DOM解析,会阻塞DOM渲染
DOM的解析和CSSOM的解析是一个并行的过程,二者会不影响 。两者解析完成之后,会合并生成 tree,之后就是和paint阶段,渲染到页面中 。
link标签不会向引用外部脚本的标签一样会触发页面的Paint 。浏览器并行解析生成DOM树和CSS树,当两者都解析完毕,才会生成渲染树,页面才会渲染 。所以应尽量减小引入样式文件的大小,提高首屏的展示速度 。
link标签会堵塞JS执行
JS运行时,可能会请求样式信息,如果此时还没有加载和解析样式,JS可能会得到错误的信息,产生很多问题,因此浏览器在link标签加载和解析过程中,会禁止脚本运行,即link标签会阻塞其后标签的执行 。
标签放在哪里合适
标签一般放在文档头部或尾部 。头部是指head标签里面,尾部一般指body结束标签之前 。将标签放在head里面,浏览器发现标签时,会优先下载脚本内容,之后在往下解析其他DOM节点 。
浏览器不能多个JS并发一起下载,最多只能同时下载两个JS脚本,且浏览器下载JS时,会暂停DOM的解析 。因此,将标签放在头部,会让网页内容呈现滞后,导致用户感觉到卡,所以如非必要,推荐将之放在尾部,以此加速网页的加载 。
将标签放在尾部也是有缺点的,如此浏览器只能先解析完整个HTML页面,才能去下载JS 。而对于一些高度依赖JS的网页,会显得慢了,因此将放在尾部也不是最优解 。