Defer
推迟执行脚本
HTML 4.01为<script>元素定义了一个叫defer的属性。这个属性表示脚本在执行的时候不会改变页面的结构。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置defer属性,相当于告诉浏览器立即下载,但延迟执行。
```
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script defer src="example1.js"></script>
<script defer src="example2.js"></script>
</head>
<body>
<!-- 这里是页面内容 -->
</body>
</html>
```
虽然这个例子中的<script>元素包含在页面的<head>中,但它们会在浏览器解析到结束的</html>标签后才会执行。HTML5规范要求脚本应该按照它们出现的顺序执行,因此第一个推迟的脚本会在第二个推迟的脚本之前执行,而且两者都会在DOMContentLoaded事件之前执行。不过在实际当中,推迟执行的脚本不一定总会按顺序执行或者在DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本。
defer属性只对外部脚本文件才有效。这是HTML5中明确规定的,因此支持HTML5的浏览器会忽略行内脚本的defer属性。IE4~7展示出的都是旧的行为,IE8及更高版本则支持HTML5定义的行为。
对defer属性的支持是从IE4、Firefox 3.5、Safari 5和Chrome 7开始的。其他所有浏览器则会忽略这个属性,按照通常的做法来处理脚本。考虑到这一点,还是把要推迟执行的脚本放在页面底部比较好。
注意 对于XHTML文档,指定defer属性时应该写成defer="defer"
Async
异步执行脚本
HTML5为<script>元素定义了async属性。从改变脚本处理方式上看,async属性与defer类似。当然,它们两者也都只适用于外部脚本,都会告诉浏览器立即开始下载。不过,与defer不同的是,标记为async的脚本并不保证能按照它们出现的次序执行,比如:
```
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script async src="example1.js"></script>
<script async src="example2.js"></script>
</head>
<body>
<!-- 这里是页面内容 -->
</body>
</html>
```
在这个例子中,第二个脚本可能先于第一个脚本执行。因此,重点在于它们之间没有依赖关系。给脚本添加async属性的目的是告诉浏览器,不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本。正因为如此,异步脚本不应该在加载期间修改DOM。
异步脚本保证会在页面的load事件前执行,但可能会在DOMContentLoaded之前或之后。Firefox 3.6、Safari 5和Chrome 7支持异步脚本。使用async也会告诉页面你不会使用document.write,不过好的Web开发实践根本就不推荐使用这个方法。
注意 对于XHTML文档,指定async属性时应该写成async="async"
总结:
defer和async加在scirpt标签上,在html解析到scirpt标签时,都会立即加载,加载不会阻塞html的解析。
defer的脚本会延迟到html解析完,DOMContentLoaded之前执行,并且多个defer会根据编写顺序从上至下。
但在各种浏览器的实际实现中,推迟执行的脚本不一定总会按顺序执行或者在DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本。
对defer属性的支持是从IE4、Firefox 3.5、Safari 5和Chrome 7开始的。其他所有浏览器则会忽略这个属性,按照通常的做法来处理脚本。考虑到这一点,还是把要推迟执行的脚本放在页面底部比较好
async脚本不会按顺序执行,也不会等待html解析完,而是下载完立刻执行,因此它的执行顺序不可控,因此不要在加了async的脚本中操作dom,但是他会保证在load事件执行完,且不要在async的代码中编写document.write。