当script上有defer或async属性时,script的下载均不会阻塞html的解析,但是一旦含有async属性的脚本被下载完,它就会立即执行(执行时会阻塞html的解析),而含有defer属性的脚本则是在html解析完后(DOMContentLoaded触发前)才执行;没有defer或async属性的脚本在下载时会阻塞html的解析,一旦其下载完它还会继续阻塞html的解析;具体可见下图:
image.png
图片来源 https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html
拿个超简单的页面测试一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0,user-scalable=no" name="viewport">
<title>Title</title>
<script src="js/defer.js" defer></script>
<script src="js/no.js"></script>
<script src="js/async.js" async></script>
</head>
<body>
<div class="cainiao">测试script上defer及async属性</div>
<!--<script type="text/javascript">-->
<!--alert(str);//因为没有定义str,所以浏览器会出错,下面的不能运行-->
<!--alert("我是代码块一");//没有运行到这里-->
<!--var test = "我是代码块一变量";-->
<!--</script>-->
<!--<script type="text/javascript">-->
<!--alert("我是代码块二"); //这里有运行到-->
<!--alert(test);-->
<!--</script>-->
</body>
</html>
image.png
结果你可能觉得有点出乎意外,为什么defer会比async先执行?不是defer等到html解析完后才执行的吗?为什么它比async先执行? 其实仔细想想,defer是在html解析完后(DOMContentLoaded事件前)执行的,由于测试的页面比较简单,因此可能DOMContentLoaded事件完成后,async的脚本才下载完,所以async才被执行;当然这只是我们的分析,我们可以拿各个阶段的时间对比一下;接下来,我们来通过js获取相应的时间戳来验证这个想法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0,user-scalable=no" name="viewport">
<title>Title</title>
<script>
window.addEventListener('DOMContentLoaded',function () {
console.log('DOMContentLoaded的时间戳是'+new Date().getTime())
})
function getAsyncLoadTime() {
console.log('async load的时间戳是'+new Date().getTime())
}
</script>
<script src="js/defer.js" defer></script>
<script src="js/no.js"></script>
<script src="js/async.js" async onload="getAsyncLoadTime()"></script>
</head>
<body>
<div class="cainiao">测试script上defer及async属性</div>
<!--<script type="text/javascript">-->
<!--alert(str);//因为没有定义str,所以浏览器会出错,下面的不能运行-->
<!--alert("我是代码块一");//没有运行到这里-->
<!--var test = "我是代码块一变量";-->
<!--</script>-->
<!--<script type="text/javascript">-->
<!--alert("我是代码块二"); //这里有运行到-->
<!--alert(test);-->
<!--</script>-->
</body>
</html>
image.png
上面的测试数据验证了我们的想法, 我后来刷新很多次,极少数也会出现下面的结果
image.png
拿个复杂一点的页面测试一下:
image.png
网友评论