在谈JS——浏览器解释script标签时默认阻塞后续DOM解析

议题

<script>的解析会阻塞DOM的解析,如果将<script>放到<head>中,则<body>中的页面内容需要等到脚本下载并编译完成才可以渲染;早期<script>中的defer属性定义延迟脚本,或是async属性定义异步脚本,都是为了让脚本解析时不阻塞后续DOM的解析;现在最常用的做法是将<script>放到<body>结束的地方,也就是</body>的上方

再谈JS——<script>的位置

以下内容来自JavaScript高级程序设计(第三版)

标签的位置

按照传统的做法,所有<script>元素都应该放在页面的<head>元素中,例如:

<!DOCTYPE html> 
<html>   
	<head>     
		<title>Example HTML Page</title>     
		<script type="text/javascript" src="example1.js"></script>     
		<script type="text/javascript" src="example2.js"></script>   
	</head>  
	 <body>    
	  	<!-- 这里放内容 -->   
	 </body>
</html> 
 

这种做法的目的就是把所有外部文件(包括 CSS文件和 JavaScript文件)的引用都放在相同的地方。 可是,在文档的<head>元素中包含所有 JavaScript文件,意味着必须等到全部 JavaScript代码都被下载、 解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到<body>标签时才开始呈现内容)。对于 那些需要很多 JavaScript 代码的页面来说,这无疑会导致浏览器在呈现页面时出现明显的延迟,而延迟 期间的浏览器窗口中将是一片空白。为了避免这个问题,现代 Web 应用程序一般都把全部 JavaScript引 用放在<body>元素中页面内容的后面,如下例所示:

<!DOCTYPE html> 
<html>   
	<head>     
		<title>Example HTML Page</title>  
	 </head>   
	 <body>     
	 	<!-- 这里放内容 -->    
	 	

	 	<script type="text/javascript" src="example1.js"></script> 
	    	<script type="text/javascript" src="example2.js"></script>   
	 </body>
</html> 
 

这样,在解析包含的 JavaScript 代码之前,页面的内容将完全呈现在浏览器中。而用户也会因为浏 览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。

延迟脚本

HTML 4.01为<script>标签定义了 defer属性。这个属性的用途是表明脚本在执行时不会影响页 面的构造。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置 defer属性,相当于告诉浏览器立即下载,但延迟执行。

<!DOCTYPE html>
<html>   
	<head>     
		<title>Example HTML Page</title>
	    	<script type="text/javascript" defer="defer" src="example1.js"></script>    
	     	<script type="text/javascript" defer="defer" src="example2.js"></script>   
	</head>  
	<body>     
	<!-- 这里放内容 -->   
	</body>
</html>	

在这个例子中,虽然我们把<script>元素放在了文档的<head>元素中,但其中包含的脚本将延迟 到浏览器遇到</html>标签后再执行。HTML5 规范要求脚本按照它们出现的先后顺序执行,因此第一 个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于 DOMContentLoaded 事件(详见第 13章) 执行。在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在 DOMContentLoaded 事件触发 前执行,因此好只包含一个延迟脚本。 前面提到过,defer 属性只适用于外部脚本文件。这一点在 HTML5 中已经明确规定,因此支持 HTML5的实现会忽略给嵌入脚本设置的 defer 属性。IE4~IE7还支持对嵌入脚本的 defer 属性,但 IE8及之后版本则完全支持 HTML5规定的行为。 IE4、Firefox 3.5、Safari 5和 Chrome是早支持 defer 属性的浏览器。其他浏览器会忽略这个属 性,像平常一样处理脚本。为此,把延迟脚本放在页面底部仍然是佳选择。

异步脚本

HTML5为<script>元素定义了 async 属性。这个属性与 defer 属性类似,都用于改变处理脚本的行为。同样与 defer 类似,async 只适用于外部脚本文件,并告诉浏览器立即下载文件。但与 defer 不同的是,标记为 async 的脚本并不保证按照指定它们的先后顺序执行。例如:

<!DOCTYPE html> 
<html>     
	<head>     
		<title>Example HTML Page</title>     
		<script type="text/javascript" async src="example1.js"></script>     
		<script type="text/javascript" async src="example2.js"></script>	
	</head>   
	<body>     
		<!-- 这里放内容 -->   
	</body> 
</html> 

在以上代码中,第二个脚本文件可能会在第一个脚本文件之前执行。因此,确保两者之间互不依赖 非常重要。指定 async 属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。 为此,建议异步脚本不要在加载期间修改 DOM。 异步脚本一定会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 事件触发之前或之 后执行。支持异步脚本的浏览器有 Firefox 3.6、Safari 5和 Chrome。

发布了65 篇原创文章 · 获赞 58 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/AngelLover2017/article/details/84725054