众所周知,html中的script标签都是同步按顺序来执行的,并且在加载和执行的时候会中断DOM解析器的解析过程,下面列举一个简单的例子来观察这一过程:
loadjs.html代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Load Script</title>
</head>
<body>
<h1>Load javascript testing</h1>
<script type="text/javascript" src="./js/a.js" ></script>
<script type="text/javascript" src="./js/b.js" ></script>
<h2>defer & async</h2>
</body>
</html>
这里为了有利于观察,在加载a.js这个文件时后台服务会增加一个延迟5s的响应时间
页面显示效果一:
我们可以看到页面先显示"Load javascript testing", 等待5秒之后才显示"defer & async",很显然,加载和执行js脚本确实中断了DOM的解析和渲染。
html5中script标签支持async和defer属性,这两个属性是做什么的呢,查看w3c文档你可以知道如果script标签有async或者defer属性,那么加载和执行脚本将不会block DOM的解析和渲染,眼见为实:
修改loadjs.html代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Load Script</title>
</head>
<body>
<h1>Load javascript testing</h1>
<script type="text/javascript" src="./js/a.js" async></script>
<script type="text/javascript" src="./js/b.js" async></script>
<h2>defer & async</h2>
</body>
</html>
页面显示效果二:
页面是渲染不会受js脚本的影响而同时显示"Load javascript testing"和"defer & async"。
async和defer有什么区别呢,两者最重要的区别是什么时候去执行脚本:
Both async and defer scripts begin to download immediately without pausing the parser and both support an optional onload handler to address the common need to perform initialization which depends on the script. The difference between async and defer centers around when the script is executed. Each async script executes at the first opportunity after it is finished downloading and before the window’s load event. This means it’s possible (and likely) that async scripts are not executed in the order in which they occur in the page. The defer scripts, on the other hand, are guaranteed to be executed in the order they occur in the page. That execution starts after parsing is completely finished, but before the document’s DOMContentLoaded event.
loadjs.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Load Script</title>
<link rel="stylesheet" href="./style/jquery-ui.css">
</head>
<body>
<h1>Load javascript testing</h1>
<script type="text/javascript" src="./js/a.js" async></script>
<script type="text/javascript" src="./js/b.js" async></script>
<h2>defer & async</h2>
</body>
</html>
a.js内容:
var globalA = 'globalA';
var globalFunction = function(){
return 'I am global function created in a.js';
};
var globalB = 'globalB';
console.log(globalFunction());
结果:在执行
console.log(globalFunction());
时抛出异常:<span style="font-family: Arial, Helvetica, sans-serif;">Uncaught ReferenceError: globalFunction is not defined,如果就async改成defer,将不会抛出此异常</span>