为什么css要放头部,js放尾部以及async、defer该如何处理?

css要放头部,js放尾部 主要是为了将页面内容尽快的展示给用户,减少白屏时间。

接下来我们来分析下原因,但是在这之前要先清楚浏览器页面的渲染过程。

  1. DOM的解析是一个从上到下的过程
  2. 所有外链资源(css,image,script)浏览器都会以接近并发的情况来发起请求(http 1.x 同域名下不是并发,详情看这里
  3. 同一时间内的最大HTTP请求是有上限的(http 1.1浏览器会限制同一个域的同时请求数,Chrome是限制6个,总连接数是17个)
  4. 解析DOM获取DOM树,解析CSS获取CSSDOM树, 两者合成渲染树(解析与构建是同步进行的,渲染树内部是拥有布局的,以及盒子模型的)
  5. 获取到渲染树之后将会进行绘制Paint,进行像素级别的渲染,绘制到屏幕上。
  6. js会堵塞DOM树的解析
  7. 当JS面前有一个link css ,无论两者谁先下载完毕,JS都会等待CSS加载并解析完成后再执行。这是因为浏览器不知道JS是否会需要查询CSSDOM,所以需要等待CSS准备完毕
  8. 渲染必须依赖CSSDOM树,可以认为CSS是堵塞渲染,但是不堵塞DOM解析

css放头部

所以,css 如果放在标签的前面,那么当DOM树构建完成了,渲染树才构建,那么当渲染树构建完成,浏览器不得不再重新渲染整个页面,这样不仅造成了资源的浪费,效率也不高。

对用户来讲,页面重新渲染的时候也会看到页面闪动,用户体验可谓极差。

如果放在之间,浏览器边构建边渲染,效率要高的多。

js放尾部

当浏览器解析到script的时候,就会立即下载执行,中断html的解析过程,如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”。

具体的流程是这样的:

  1. 浏览器一边下载HTML网页,一边开始解析。
  2. 解析过程中,发现script标签
  3. 暂停解析,网页渲染的控制权转交给JavaScript引擎
  4. 如果script标签引用了外部脚本,就下载该脚本,否则就直接执行
  5. 执行完毕,控制权交还渲染引擎,恢复往下解析HTML网页

外链的script包含async或者defer如何处理?

这两个属性只是script标签在header标签中使用的,如果你把它放在body后面是无效的。

script 的这两个属性主要用于其js文件没有操作DOM的情况,这时候就可以将该js脚本设置为异步加载,通过async或defer来标记代码

async和defer的区别:

  1. async和defer都仅对外部脚本有效,对于内置而不是连接外部脚本的script标签,以及动态生成的script标签不起作用。
  2. async和defer虽然都是异步的,不过使用async标志的脚本文件一旦加载完成就会立即执行;而使用defer标记的脚本文件,会在 DOMContentLoaded 事件之前(也就是页面DOM加载完成时)执行。
  3. 如果有多个js脚本文件,async标记不保证按照书写的顺序执行,哪个脚本先下载结束,就先执行那个脚本。而defer标记则会按照js脚本书写顺序执行。
  4. 一般来说,如果脚本之间没有依赖关系,就使用async属性,如果脚本之间有依赖关系,就使用defer属性。如果同时使用async和defer属性,后者不起作用,浏览器行为由async属性决定。

对于async标记,浏览器的解析过程是这样的:

  • 浏览器开始解析HTML网页
  • 解析过程中,发现带有async属性的script标签
  • 浏览器继续往下解析HTML网页,同时并行下载script标签中的外部脚本
  • 脚本下载完成,浏览器暂停解析HTML网页,开始执行下载的脚本
  • 脚本执行完毕,浏览器恢复解析HTML网页

对于defer标记,浏览器的解析过程是这样的:

  • 浏览器开始解析HTML网页
  • 解析过程中,发现带有defer属性的script标签
  • 浏览器继续往下解析HTML网页,同时并行下载script标签中的外部脚本
  • 浏览器完成解析HTML网页,此时再执行下载的脚本

由于使用了async或defer的script会放在header中,而header又会存在外链css,那么二者有顺序要求吗?

因为 js 的执行是依赖 css 样式 的。即只有 css 样式全部下载完成后才会执行js。

由于现代浏览器很聪明会进行 prefetch 优化,就如 Chrome 浏览器,它会在解析 HTML 时收集外链,并在后台并行下载,由于会并行下载,那么head中外链js和css的位置其实就没有什么很大影响了。

参考:
https://juejin.cn/post/6844904009694707725#heading-2
https://www.zhihu.com/question/23250329
https://www.cnblogs.com/huaweiyun/p/13202745.html
https://yinode.tech/post/201901/从js的阻塞角度谈谈浏览器渲染原理/#情况2-css放头部-js放-body-前