我们先来看一段代码,html中使用script标签引入了script1.js、script1.js和script3.js
三个文件。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>TEST HTML</title>
</head>
<script src="script1.js"></script>
<script src="script2.js"></script>
<script src="script3.js"></script>
<body>
<p>test</p>
</body>
</html>
我们开发的时候一般都说要把 <script>
放到 body
体的最后,也就是 </body>
之前,你要是不理解为什么这么做的话,我们来看浏览器遇到了上面这段代码,它是怎么干活的。
-
浏览器会解析HTML,一直到
script
标签,也就是这部分代码,对应上图中的蓝线
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>TEST HTML</title> </head>
-
遇到了
script
会通过src找到对应的js文件,进行下载(绿线
),加载完成会执行(红线
),注意,注意这个时候html是不会向下解析的
,一直等到所有的script文件执行完成<script src="script1.js"></script> <script src="script2.js"></script> <script src="script3.js"></script>
-
然后解析剩下的html (
蓝线
)<body> <p>test</p> </body> </html>
第二步加载JavaScript会阻碍html的解析,如果js文件很大,我们会一直等到js文件执行完了,解析后面的html我们才能在浏览器中看到页面,还有一个要是js中操作dom元素的话,很抱歉这个时候html都没解析完,找不到操作的元素。是不是理解为什么要把script放到最后了?script脚本阻碍html解析
,阻碍时间长了就出现白屏
了。
defer
修改之前的代码,script标签添加defer属性
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>TEST HTML</title>
</head>
<script src="script1.js" defer></script>
<script src="script2.js" defer></script>
<script src="script3.js" defer></script>
<body>
<p>test</p>
</body>
</html>
脚本会被延迟到整个页面都解析完毕后再执行,如下图:
- 同之前一样,浏览器会解析HTML,一直到
script
标签 - 遇到script标签同时有defer属性,脚本文件会加载,但是html继续解析
- 等待
html解析完毕
,script中的代码开始执行
async
我们来看另一个属性async,修改代码为:
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>TEST HTML</title>
</head>
<script src="script1.js" async></script>
<script src="script2.js" async></script>
<script src="script3.js" async></script>
<body>
<p>test</p>
</body>
</html>
脚本文件会在下载完成后执行
- 同之前一样,浏览器会解析HTML,一直到
script
标签 - 遇到script标签同时有async属性,脚本文件会加载,但是html继续解析
- 只要任意一个带有async的script脚本先加载完毕,就会直接执行,
各个文件的执行顺序不定
同时添加defer和async
-
表现和async一致
-
不支持async的浏览器,支持defer的,会表现得和defer一样
-
- 异步加载 比延迟执行的 优先级高些
-
这种方法,是同时兼容 支持async和defer 两个属性的浏览器的一种办法
-
如果 script 无 src 属性,则 defer, async 会被忽略
最后
还是回到最初的那个问题:为什么要把把<script>
写在<body>
底部?
因为这样,没有兼容性问题,没有白屏问题,没有执行顺序问题。就一句:可以放心下班了。