浏览器的阻塞渲染

前面的话

在浏览器拿到HTML、CSS、JS等外部资源到渲染出页面的过程中,会存在css与Javascript的阻塞资源。这篇文章介绍css与Javascript是如何阻塞资源的。

1: css被视为渲染阻塞资源,这意味着浏览器将不会渲染任何已处理的内容,直至 CSSOM 构建完毕,才会进行下一阶段。

2: JavaScript 被认为是解释器阻塞资源,HTML解析会被JS阻塞,它不仅可以读取和修改 DOM 属性,还可以读取和修改 CSSOM 属性。

下面来看看 CSS 与 JavaScript 是具体如何阻塞资源的。

css
<style>p {color:red;} </style>
<link rel="stylesheet" href="index.css">

这样的 link 标签(无论是否 inline)会被视为阻塞渲染的资源,浏览器会优先处理这些 CSS 资源,直至 CSSOM 构建完毕。

解决方法:

  • 精简 CSS 并尽快提供它。
  • 媒体类型(media type)和媒体查询(media query)来解除对渲染的阻塞。
<link href="index.css" rel="stylesheet">

<link href= "print.css" rel="stylesheet" media="print">

<link href="other.css" rel="stylesheet" media="(min-width: 30em) and (orientation: landscape)">

第一个资源会加载并阻塞。第二个资源设置了媒体类型,会加载但不会阻塞,print 声明只在打印网页时使用。第三个资源提供了媒体查询,会在符合条件时阻塞渲染。

关于CSS加载的阻塞情况:

  • css加载不会阻塞DOM树的解析

  • css加载会阻塞DOM树的渲染

  • css加载会阻塞后面js语句的执行

没有js的理想情况下,html与css会并行解析,分别生成DOM与CSSOM,然后合并成Render Tree,进入Rendering Pipeline;但如果有js,css加载会阻塞后面js语句的执行,而(同步)js脚本执行会阻塞其后的DOM解析(所以通常会把css放在头部,js放在body尾)

JavaScript

如果没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script标签之下的HTML元素之前,也就是说不等待后续载入的HTML元素,读到就加载并执行。

解析过程中无论遇到的JavaScript是内联还是外链,只要浏览器遇到 script 标记,唤醒 JavaScript解析器,就会进行暂停 (blocked )浏览器解析HTML,并等到 CSSOM 构建完毕,才去执行js脚本。因为脚本中可能会操作DOM元素,而如果在加载执行脚本的时候DOM元素并没有被解析,脚本就会因为DOM元素没有生成取不到响应元素,所以实际工程中,我们常常将资源放到文档底部。

解决方法:

  • 改变脚本加载次序:就要提到defer与async

defer 与 async 可以改变之前的那些阻塞情形,这两个属性都会使 script 异步加载,然而执行的时机是不一样的。注意 async 与 defer 属性对于 inline-script 都是无效的, 所以下面这个示例中三个 script 标签的代码会从上到下依次执行。

<script async> console.log("1")< /script>
<script defer> console.log("2")< /script>
<script> console.log("3")< /script>

下面分别讨论defer与async的区别:
在这里插入图片描述

defer:
<script src="app1.js"  defer> < /script>
<script src="app2.js"  defer> < /script>
<script src="app3.js"  defer> < /script>

defer 属性表示延迟执行引入 JavaScript,即 JavaScript 加载时 HTML 并未停止解析,这两个过程是并行的。 整个HTML解析完毕且defer-script也加载完成之后,才会执行所有由defer-script加载的JavaScript代码,再触发 DOMContentLoaded(初始的 HTML 文档被完全加载和解析完成之后触发) 事件。

defer 不会改变 script 中代码的执行顺序,示例代码会按照 1、2、3 的顺序执行。

所以,defer 与相比普通 script,有两点区别:载入 JavaScript 文件时不阻塞 HTML 的解析,执行阶段被放到 HTML 的解析完成之后。

async

async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行,无论此刻是 HTML 解析阶段还是 DOMContentLoaded 触发(HTML解析完成事件)之后。

从上一段也能推出,多个 async-script 的执行顺序是不确定的,谁先加载完谁执行。

注意:向 document 动态添加 script 标签时,async 属性默认是 true。即:使用 document.createElement 创建的 script 默认是异步的。

console.log(document.createElement("script").async);// true

所以,通过动态添加 script 标签引入 JavaScript 文件默认是不会阻塞页面的。如果想同步执行,需要将 async 属性人为设置为 false。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值