通常我们把script标签放在body尾部,link标签放在head头部,通过CDN引入第三方库时,放在link标签前面
概括
CSS
不会阻塞DOM
解析,但是会阻塞DOM
渲染,严谨一点则是CSS
会阻塞render tree
的生成,进而会阻塞DOM
的渲染JS
会阻塞DOM
解析CSS
会阻塞JS
的执行- 浏览器遇到
<script>
标签且没有defer
或async
属性时会触发页面渲染 Body
内部的外链CSS
较为特殊,会形成FOUC
(样式闪烁)现象,请慎用
css不会阻塞DOM解析,会阻塞dom渲染
- DOM树和CSSOM树的解析是互不影响的,因此css不会阻塞页面的解析
- 但是由于render树的生成是依赖DOM树和CSSOM树,因此CSS必然会阻塞DOM的渲染
- css会阻塞rrender树的生成,进而会阻塞dom的渲染
js会阻塞dom解析
- first paint
- 改变dom
css会阻塞js的执行
- 如果js脚本中是获取dom元素的css样式属性,为了获取到最新的正确的样式,需要所有的css加载完成,否则获取的样式可能是错误的或者不是最新的
- 要等到js脚本前面的css加载完成,js才能再执行
- 所以一般cdn引入第三方库的script一般放在link之前
js触发页面渲染
- 浏览器解析DOM时,虽然是一行一行地向下执行,但是它会预先加载具有引用标记的外部资源(例如带有src标记的script标签)
- 在解析到此标签的时候,则无需再去加载,直接运行,以此提高运行效率
- 浏览器无法预先知道脚本的具体内容,因此碰到script标签时,只好先渲染一次页面,确保script脚本内能获取到dom最新的样式
- 如果在决定渲染页面时,还有尚未加载完成的css文件,只能等待其加载完成再去渲染页面
body内的CSS(link)
- body内的css属于特殊情况,会因浏览器的差异,呈现不同的表现形式,这种现象叫做FOUC(样式闪烁),代码中应当尽量避免
script标签中async和defer的区别
defer
- 脚本被延迟到整个页面都解析完毕后再运行(立即下载,但延迟执行)
- defer属性仅适用于外部脚本(用src引入的脚本),浏览器会忽略行内脚本的defer属性
- 若多个script含defer属性,推迟执行的脚本不一定总会按照顺序来执行或者在DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本
- 不是所有浏览器都支持这个属性,因此把推迟执行的脚本文件放在body底部比较好(IE4、Firefox 3.5、Safari 5 和 Chrome 7 支持)
async
- 与defer类似的是,它们都适用于外部脚本,都会告诉浏览器立即开始下载
- 标记为async的脚本并不保证能按照它们出现的次序执行
- 既没有defer也没有async,则浏览器遇到script标签时,会立即加载并执行指定的脚本,执行完毕之后,才继续解析后面的标签
- 有async属性,浏览器遇到该script标签时,加载脚本的过程与解析后面标签的过程同时进行,加载完毕后,立即执行该脚本
- 有defer属性,浏览器遇到该script标签时,加载脚本的过程与解析后面标签的过程同时进行。但是执行脚本的过程,在解析完所有元素之后才执行。(加载完脚本后,将执行推迟到页面解析完之后)