HTML5中<script>标签中的defer与async属性详解

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介:    在HTML中执行脚本最重要的方法就是使用<script>元素,但是执行<script>元素时会阻塞后面文档的加载。 那么首先为什么会阻塞呢,是由于哪些原因呢? 其实是<script>标签中的src属性在作怪,因为一个src就相当于一次http请求,他的作用就是把src所对应的地址上的文档下载到本地,因此当浏览器碰到<scrip

   在HTML中执行脚本最重要的方法就是使用<script>元素,但是执行<script>元素时会阻塞后面文档的加载。

那么首先为什么会阻塞呢,是由于哪些原因呢?

其实是<script>标签中的src属性在作怪,因为一个src就相当于一次http请求,他的作用就是把src所对应的地址上的文档下载到本地,因此当浏览器碰到<script>标签时,严格的说也就是src时,他会立即停止HTML文档的解析,而去下载并且执行脚本,当脚本执行完毕才会继续解析HTML文档。这就是形成阻塞的原因,

这里不得不提的是,<a>标签中的href属性,它的意义只是把此文档和href后面跟的文档建立连接关系,而不用下载,这就是他与src的区别。

    为了解决这个问题HTML5<script>元素添加了asyncdefer属性。

一、浏览器加载到<script>元素,没有设置async或者defer

<code class="hljs xml has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"main.js"</span>></span><span class="javascript" style="box-sizing: border-box;"></span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

       浏览器执行到这个元素的时候会立即下载src所指向的脚本并且执行,在执行完该脚本以后再加载这个<script>元素后面的文档。

二、当浏览器执行到<script>元素,元素设置了async属性

<code class="hljs xml has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">async</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"main.js"</span>></span><span class="javascript" style="box-sizing: border-box;"></span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

       当浏览器解析到这个<script>元素的时候,会立即下载该脚本,但是不糊阻塞页面中的其他操作,比如其他脚本的加载和页面的渲染。加载和渲染后续文档的过程和加载main.js并行执行(异步)。

       async不能保证按照脚本出现的先后顺序执行,所以,确保该脚本和其他文档的相互依赖关系非常重要,指定async的目的是让页面不用等待这个脚本加载完毕以后再继续下一步操作,让指定async的脚本和后续文档异步执行,所以设置异步加载的脚本最好不要操作DOM,因为不知道他什么时候执行,容易产生错误。

       async脚本会在页面的load事件之前执行,但是不一定在DOMContentLoaded事件之前执行,有可能在这个事件之前或者之后执行。支持async的浏览器有:Firefox 3.6、Safari 5 和Chrome。

三、当浏览器解析到<script>,元素设置了defer属性

<code class="hljs xml has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">defer</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"main_1.js"</span>></span><span class="javascript" style="box-sizing: border-box;"></span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">defer</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"main_2.js"</span>></span><span class="javascript" style="box-sizing: border-box;"></span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">script</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

       当元素加载到<script>元素,该元素设置了defer时,会立即下载该脚本,但是会延迟执行,加载后续文档的过程会和该脚本并行进行(异步),它会在所有文档解析之后,在DOMContentLoaded事件执行之前完成。和async不同的还有一点是设置了defer的脚本会按照它出现在HTML页面中的顺序执行。

四、总结

       从实际角度出发,还是把<script>放在body的底部比较合适,对于比较旧的浏览器这是最好的优化方式,并且能够保证非脚本的文档以最快的速度解析。

下面来看一张图: 
script 
上图中,绿色代表HTML文档解析; 
蓝色代表网路读取,红色代表执行时间,这两个是针对脚本的。

从上图中我们可以得出以下几点总结:

  1. asyncdefer在网络读取这一部分是一样的,即下载脚本的时候都是异步的。
  2. asyncdefer很明显的差别在于执行时间不同,async在加载完之后就执行,而defer是在页面解析之后执行,显然defer更接近我们对于脚本执行的要求。
  3. 关于defer,图中没有表现出来的是defer是按照顺序执行脚本的。
  4. 关于defer ,并不能保证执行的顺序,它加载和执行是紧紧挨着的,加载完后就立即执行,不管你声明的顺序如何,都不知道它是什么时候执行的。
  5. 因为async不能保证脚本执行的顺序,所以要设置async的脚本一定要和其他脚本没有依赖关系,并且不操作DOM。
目录
相关文章
|
3月前
|
移动开发 搜索推荐 UED
HTML5的新语义化标签
HTML5引入的这些新语义化标签,通过明确标识内容的结构和意义,使得网页结构更加清晰,易于理解和维护。使用这些标签不仅提升了网页的可读性和可访问性,还增强了搜索引擎和辅助技术对网页内容的解析能力。在实际开发中,合理使用这些语义化标签,能够显著提升网页的质量和用户体验。
109 49
|
3月前
|
移动开发 HTML5
HTML5 表单属性3
`&lt;input&gt;` 标签的 `formaction`、`formenctype` 和 `formmethod` 属性分别用于指定表单提交的 URL 地址、数据编码类型和提交方法,这些属性可覆盖 `&lt;form&gt;` 标签中的相应属性,并且主要适用于 `type=&quot;submit&quot;` 和 `type=&quot;image&quot;` 的输入类型。
|
2月前
|
移动开发 JavaScript 前端开发
HTML5 表单属性7
`pattern` 属性使用正则表达式验证 `&lt;input&gt;` 元素的值,适用于 `text`, `search`, `url`, `tel`, `email`, 和 `password` 类型。
|
2月前
|
移动开发 UED HTML5
HTML5 表单属性6
`min`、`max` 和 `step` 属性用于限制 `&lt;input&gt;` 标签中的数值或日期范围。例如,可以设置日期选择器的最早和最晚日期,或限制数字输入框的值范围。`multiple` 属性允许在 `&lt;input&gt;` 中选择多个值,适用于邮箱和文件类型。这些属性增强了表单控件的功能性和用户体验。
|
2月前
|
移动开发 HTML5
HTML5 表单属性5
`height` 和 `width` 属性用于 `&lt;input&gt;` 标签中的 `image` 类型,定义图像的高度和宽度。
|
3月前
|
移动开发 HTML5
HTML5 表单属性4
`formnovalidate` 属性是一个布尔属性,用于 `&lt;input&gt;` 元素,指示该输入在表单提交时不需验证,可覆盖 `&lt;form&gt;` 元素的 `novalidate` 属性,常与 `type=&quot;submit&quot;` 一起使用。示例中展示了如何通过两个提交按钮(一个使用验证,另一个不使用)实现不同的表单提交方式。
|
3月前
|
移动开发 JavaScript 前端开发
HTML5 表单属性2
`novalidate` 是 HTML `&lt;form&gt;` 元素的布尔属性,用于禁用浏览器的默认表单验证功能。当此属性存在时,浏览器不会检查表单字段是否符合预设的验证规则,允许开发者通过 JavaScript 等手段自定义验证逻辑。
|
2月前
|
移动开发 数据安全/隐私保护 HTML5
HTML5 表单属性8
`required`属性确保表单提交前输入框不能为空,适用于多种类型的 `&lt;input&gt;` 标签,如文本、邮箱、密码等。`step`属性则用于指定输入域中合法数值的间隔,常与`max`和`min`属性配合使用,适用于数字、日期等类型。例如,设置`&lt;input type=&quot;number&quot; step=&quot;3&quot;&gt;`可使输入值以3为单位递增或递减。
|
3月前
|
存储 移动开发 前端开发
高效的 HTML 与 CSS 编写技巧,涵盖语义化标签、文档结构优化、CSS 预处理、模块化设计、选择器优化、CSS 变量、媒体查询等内容
本文深入探讨了高效的 HTML 与 CSS 编写技巧,涵盖语义化标签、文档结构优化、CSS 预处理、模块化设计、选择器优化、CSS 变量、媒体查询等内容,旨在提升开发效率、网站性能和用户体验。
86 5
|
3月前
|
移动开发 UED HTML5
HTML5 表单属性1
HTML5为&lt;form&gt;和&lt;input&gt;标签引入了多个新属性,增强了表单的功能性和用户体验。其中,&lt;form&gt;新增了autocomplete和novalidate属性;&lt;input&gt;则增加了如autofocus、formaction、placeholder等13个新属性,支持更精细的表单控制和数据验证。例如,autocomplete属性允许表单或输入字段提供自动完成功能,提高用户填写效率。

热门文章

最新文章