js 脚本位置和执行

参考 高性能javascript

  当浏览器解析到<script>标签的时候,无论这个js代码是内嵌的还是外链的,都会导致页面的下载和渲染阻塞,当js代码下载并执行完毕后,继续页面的下载和渲染(因为脚本的执行过程可能会存在修改页面内容的情况,所以会阻塞页面的下载和渲染)

  我们可以将<script>放在页面的<head>或者<body>,首先我们先将<script>标签放在<head>中

  

<!DOCTYPE html>
<head>
    <meta charset="UTF-8" />
    <script type="text/javascript" src="a.js"></script>
    <script type="text/javascript" src="b.js"></script>
    
</head>
<body>
    <p>hello</p>
</body>

当以上面的方式放置并加载js代码时,由于js代码会阻塞页面的渲染和其他的元素的下载(允许js并行下载),会导致延迟,变现为页面的空白并且用户无法与页面进行交互

因此推荐将<script>标签放在页面的<body>标签的底部

<!DOCTYPE html>
<head>
    <meta charset="UTF-8" />
</head>
<body>
    <p>hello</p>


    <script type="text/javascript" src="a.js"></script>
    <script type="text/javascript" src="b.js"></script>
</body>

这样当下载和执行js代码的时候页面的大部分内容已经下载完成并显示给了用户。

由于<script>标签会阻塞页面的渲染(即使将<script>标签放在页面的底部,会阻塞未下载完成的其他非js元素)而且还会因为脚本的执行导致一定的延迟,所以最小化延迟时间会改善页面的总体性能

当处理外链的javascript文件时,http请求会带来相应开销,因此我们可以减少外链脚本文件的数量,例如可以通过雅虎的合并处理器,可以通过一个url加载多个js文件(注意这些文件在服务器是独立存在的如果简单的将两个js文件在服务器中合并,在加载的时候只加载合并的文件,这样不仅导致文件的体积变大造成更大的延迟也缺少复用的可能)


无阻塞脚本

  通过减少js文件大小并限制http请求数可以提高一定的页面性能,当时当页面越来越复杂的时候,精简源代码并不是总可行,因此提出了无阻塞脚本即在页面加载完成后才加载js代码也就是在window对象的onload事件触发后在下载脚本

1)延迟脚本 defer

这并不是一个理想的跨浏览器解决方案,当我们为<script>标签设置defer属性时,就指明了该元素所含的脚本不会修改DOM,因此代码能安全的延迟执行,但是不支持defer属性的浏览器的时候,<script>标签会以默认的方式处理(阻塞),带有defer属性的<script>可以放在页面的任何位置,在解析到这个<script>标签时候开始现在但不会执行直到DOM加载完成(onload事件被触发前执行),带有defer属性的<script>标签文件下载时,不会阻塞浏览器的其他进程,可以与页面的其他资源并行下载

2)动态脚本元素

这种方法是用标准的DOM方法创建新的<script>元素

     var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "a.js";
        document.getElementsByTagName("head")[0].appendChild(script);

以这种方式创建并且加载js文件,文件在该元素被添加到页面的时候开始下载,并且在下载和执行的过程中不会阻塞页面的其他进程

但是当这种方式加载js代码,提供的页面其他脚本调用的借口时(提供函数供其他部分使用),就必须确保脚本下载完成并准备就绪

在非IE浏览器中 <script>标签在接收完成时触发一个load事件,可以通过侦听此事件来获得脚本加载完成时的状态

在IE浏览器中 会触发readystatechange事件,主要同时检测两个状态 loaded complete 只要满足其中的一个触发,就删除事件处理器(确保事件不会处理两次)

下面就是相应的方法实现(跨浏览器实现)

<script type="text/javascript">
		function loadScript(url,callback) {
			var script = document.createElement("script");
			script.type = "text/javascript";

			if(script.readyState) {//IE
				script.onreadystatechange = function() {
					if(script.readyState == "loaded" || script.readyState == "complete") {
						script.onreadystatechange = null;
						callback();
					}
				};
			} else {//非IE
				script.onload = function() {
					callback();
				}
			}

			script.src = url;
			document.getElementsByTagName(‘head‘)[0].appendChild(script);
		}
	</script>

  

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。