《高性能javascript》读书笔记--js脚本的加载与执行

第一章 加载与执行

JS在浏览器中的性能,可以认为是开放者面临的最重要可用性问题。

JS的阻塞性————多数浏览器使用单一进程处理UI和脚本,意味着<script>标签的出现会让页面等待脚本的执行(内嵌和外链),脚本执行时间越长,浏览器响应越慢。


1. 脚本位置

html规范指出<script>标签可以放在<head>或者<body>中,并允许出现多次。理论上讲,在<head>中加载JS和CSS,有助于确保页面和交互的正确性。

目前的浏览器基本都允许并行下载,外部资源同时下载,但是依然会阻塞其他资源的下载,比如图片,如图1所示,图片资源在js下载完成后才开始下载。 


图1 资源的加载

尽管脚本下载过程不会相互影响,但仍需要等待所有js下载完才可以继续,尽管允许并行下载,但脚本阻塞仍然是一个问题。

因此,书中提到雅虎特别性能小组提出优化js的首要规则:将脚本放在底部

然而,将script放在尾部的缺点,是浏览器只能先解析完整个HTML页面,再下载JS。而对于一些高度依赖于JS的网页,就会显得慢了,所以将script放在尾部也不是最优解,第3部分的无阻塞脚本会提到。

浏览器的并行下载机制

1)图片、js、css都属于静态资源,可以并行下载

2)浏览器并不是严格地按照顺序下载静态资源,它会根据优先级来安排下载顺序。

http1.1协议下的并行数量限制:

IE6:2个;

      IE7:4个;

      IE8+:6个

      FireFox,Chrome:6个。

补充同一时间针对同一域名下的请求有一定数量限制,超过限制数目的请求会被阻塞。大多数浏览器的并发数量都控制在6以内。有些资源的请求时间很长,因而会阻塞其他资源的请求。因此,对于一些静态资源,如果放到不同的域名下面就能实现与其他资源的并发请求。


2. 组织脚本

由于每个script标签初始下载时会阻塞页面渲染,所有要减少页面<script>标签数量。这不仅针对外链脚本,内嵌脚本数量也要限制。因此,常用的方法是将多个文件合并成一个,减少请求次数。


3. 无阻塞脚本

减少js文件大小并限制http请求次数仅仅是创建响应迅速的web应用第一步。当功能丰富,代码庞大的时候,精简代码,减少个数可能并不适合,因为庞大的单个js文件虽然只产生一次请求,但却会锁死浏览器相当大的时间。一些处理方法:

1)延迟脚本defer

先下载,不立即执行,直到DOM加载完(onload事件触发前)。

其中,a.js输出“defer”,b.js输出“normal”,结果是”normal”, “defer”, “load”。带有defer属性的<script>元素不是跟在第二后面执行的,而是在onload事件处理器执行前被调用

另外,在支持H5的实现会忽略defer属性,因此把延迟脚本放在页底还是最佳的选择。

2)异步脚本async

  H5点async属性与defer类似,区别在于执行的时机。async的执行比较混乱,不会在意<script>的顺序,加载完后就执行。如果项目中存在依赖关系,不推荐使用。

3)动态脚本

动态创建<script>元素加载js文件,文件在该元素被添加到页面时开始下载,返回的代码会立即执行。重点在于:无论何时启动下载,文件的下载和执行过程不会阻塞页面的其他进程。通常创建的新标签放在head里比较保险。

另外,为了确保没有问题,要跟踪脚本下载完成且准备就绪。

第一种,使用script.onload

第二种,readyState属性,五种状态:uninitialized初始状态,loading开始下载,loaded下载完成,interactive完成下载但不可用,complete准备就绪。常用loaded和complete。

var script = document.createElement("script");
    script.type = "text/javacript";
    script.src = "./b.js";
    document.body.appendChild(script);

    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 { //Others
		script.onload = function(){
			callback();
		};
	}
	script.src = url;
	document.getElementsByTagName_r("head")[0].appendChild(script);
}

可以尽可能多地动态加载,但是要考虑清楚顺序问题。所有可以使用串联调用的方法确保顺序,也可以合并后加载

4)XMLHttpRequest脚本注入

该方法是先创建XHR对象,然后下载js文件,最后动态注入。和动态注入多区别在于,下载后不会立即执行,可以推迟到你准备就绪的时候,另外,兼容性较好。

局限在于,不能跨域请求,意味着js文件不能从cdn获取,因此大型应用一般不采用。


4. 小结

管理浏览器中的JS代码并不是一个简单的事情,因为阻塞问题会影响浏览器的进程。有几种方法可以减少JS对性能的影响:

1)将 <script>标签放于页底,确保脚本执行前页面已完成渲染

2)合并脚本。<script>标签越少,加载越快,响应越迅速

3)多种无阻塞下载JS的方法:

*使用<script>的defer和async属性

*使用动态创建<script>元素的方法

*使用XHR对象下载JS代码,并注入页面

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值