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。
目录
相关文章
WK
|
3天前
|
存储 移动开发 前端开发
HTML5新增了哪些其他元素和属性
这段文字介绍了HTML5中新增的多种元素和属性,包括页面布局元素如header、nav等,表单元素如email、tel输入框等,以及其他元素如canvas、svg等。此外,还介绍了全局及表单属性,例如contenteditable、placeholder等,这些新功能显著增强了HTML5在现代网页设计与开发中的实用性与灵活性。
WK
15 1
|
9天前
|
移动开发 JavaScript 前端开发
HTML5 表单属性详解
HTML5引入了多种新的表单属性,使表单创建与验证更加便捷高效。新增的输入类型包括`email`、`url`、`tel`等,常用属性有`placeholder`、`required`等。表单元素如`&lt;form&gt;`可设置提交方法和目标URL,`&lt;button&gt;`及`&lt;input type=&quot;submit&quot;&gt;`用于提交。新元素`&lt;datalist&gt;`和`&lt;output&gt;`提供更多功能。HTML5还提供了内置表单验证机制,增强用户体验。
|
1天前
|
移动开发 HTML5
HTML5标签的类型
HTML5标签的类型。
18 5
WK
|
3天前
|
移动开发 UED HTML5
HTML5新增了哪些表单属性
HTML5新增的表单属性包括:autocomplete(启用或禁用自动完成建议)、autofocus(自动聚焦)、form(关联表单外的表单元素)、formaction等重写版本(自定义提交行为)、height/width(设置图像输入尺寸)、list(指定可选列表)、min/max/step(设置数值范围)、multiple(多选文件/选项)、pattern(正则表达式验证)、placeholder(占位符提示)和required(必填校验)。这些新功能显著提升了表单的灵活性和用户体验,使数据输入更加准确有效。
WK
8 1
|
15天前
|
前端开发
前端基础(二)_HTML常用标签(块级标签、行级标签、行块级标签)
本文详细介绍了HTML中的常用标签,包括块级标签(如`h1`至`h6`、`p`、`div`等)、行级标签(如`span`、`b`、`strong`、`i`、`em`、`sub`、`sup`、`del`、`a`等),以及行块级标签(如`img`)。文章解释了这些标签的用途、特点和基本用法,并通过示例代码展示了如何在HTML文档中使用它们。
59 1
|
15天前
|
移动开发 开发者 UED
HTML5中video标签controlslist属性的使用方法
`controlsList`属性为开发者提供了更多控制HTML5视频播放器行为的能力,让视频内容的集成更加灵活和符合需求。通过精心设计的控制列表,可以提升用户体验,同时保持内容的安全性和专业性。这种细节的控制和定制能力是现代Web开发的一个重要方面,反映了HTML5对开发者和内容创作者需求的响应。
23 1
|
16天前
|
存储 JavaScript Java
使用NekoHTML解析HTML并提取META标签内容
关于NekoHTML的代码样例,这里提供一个简单的示例,用于展示如何使用NekoHTML来解析HTML文档并提取其中的信息。请注意,由于NekoHTML的具体实现和API可能会随着版本更新而有所变化,以下代码仅供参考。 ### 示例:使用NekoHTML解析HTML并提取META标签内容 ```java import org.cyberneko.html.parsers.DOMParser; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml
|
16天前
|
XML JavaScript Java
NekoHTML 是一个基于Java的HTML扫描器和标签补全器
**NekoHTML** 是一个基于Java的HTML扫描器和标签补全器(tag balancer),由J. Andrew Clark开发。它主要用于解析HTML文档,并能够“修正”许多在编写HTML文档过程中常犯的错误,如增补缺失的父元素、自动用结束标签关闭相应的元素,以及处理不匹配的内嵌元素标签等。这使得程序能够以标准的XML接口来访问HTML文档中的信息。 ### NekoHTML的主要特点包括: 1. **错误修正**:能够自动修正HTML中的常见错误,如未闭合的标签等。 2. **DOM树生成**:将HTML源代码转化为DOM(Document Object Model)结构,便
|
16天前
|
移动开发 数据管理 HTML5
Twaver-HTML5基础学习(22)层管理容器(LayerBox)、告警管理容器(AlarmBox)、列管理容器(ColumnBox)、属性管理容器(PropertyBox)
本文介绍了Twaver HTML5中的多种管理容器:层管理容器(LayerBox)、告警管理容器(AlarmBox)、列管理容器(ColumnBox)和属性管理容器(PropertyBox)。文章解释了这些容器的作用、如何获取它们,并提供了一些基本的操作方法。这些容器分别用于管理图层、告警、表格列和属性对象,是TWaver中数据管理和组织的重要部分。
31 1
|
16天前
|
JavaScript 前端开发
react字符串转为dom标签,类似于Vue中的v-html
本文介绍了在React中将字符串转换为DOM标签的方法,类似于Vue中的`v-html`指令,通过使用`dangerouslySetInnerHTML`属性实现。
35 0
react字符串转为dom标签,类似于Vue中的v-html