script的defer和async的用法
在我们通过script标签引入外部的js文件的时候通常会将script标签写在body的最下面,body结束标签的上面。
<html>
<head>
...
</head>
<body>
...
<script src="...."></script>
</body>
</html>
这是因为在页面加载的时候会从上往下加载页面内容,当页面内容加载完成后再加载js的内容,这样就不回阻塞页面,让用户看到的空白页面时间减少些。如果将script写在网页内容上面,那么js引擎遇到script就会先加载js内容(下载,解析,运行),而网页的内容会在js文件运行完毕之后才会加载,所以用户会先看到空白页面,等待js运行完成才会呈现网页内容。
JavaScript标准给script提供了两个属性,用来设置脚本下载和执行的时间
推迟执行脚本
HTML4.01为script标签提供了一个defer属性,这个脚本表示该脚本在执行的时候不会改变页面结构,因此,这个脚本会在整个页面解析完成之后再执行,再script上加上defer属性会告诉浏览器,当遇到这个脚本的时候立即去下载这个脚本,但是执行会在页面解析完成后进行。
<html>
<head>
<title>...</title>
<script defer src="example1"></script>
<script defer src="example2"></script>
</head>
<body>
....
</body>
</html>
在上面的例子中,虽然script在head标签中,但是只会下载,不会执行,在解析完之后才会执行,并且会根据他们出现的顺序依次执行,并且两者会在DOMContentloaded
事件之前执行。
异步执行脚本
HTML5为script标签提供了async属性,梳理方式与defer大致相同,都不会导致页面渲染时间延迟。
<html>
<head>
<title>...</title>
<script async src="example1"></script>
<script async src="example2"></script>
</head>
<body>
....
</body>
</html>
当解析到有async的script标签的时候,会通知浏览器立即下载该脚本,但是执行是异步的(个人理解的异步执行是在js引擎空闲的时候执行,宏观上是跟页面渲染同步的,微观上是异步交替执行的),而且执行的时候也不会根据它们的的出现顺序来执行,例如上面的例子,可能example2先于example1执行,也可能example1先于example2执行。但是脚本都会在页面的load事件前执行,但可能会在DOMContentloaded
之前或之后。
总结
defer和async都不会延迟页面的渲染时间,在浏览器解析到有defer或者async的script标签时候都会立即下载,但是有defer的script标签会在解析结束后执行,async会异步执行。