《高性能 JavaScript》笔记(一):脚本加载和执行

1.1 把 css 放在头,把 js 放在尾

HTML、CSS 和 JavaScript 的解析任务在同一个线程的队列中进行。
脚本加载后会立即被执行,如果将脚本放在 <head> 中,需要等到脚本执行完毕,才能继续解析 <body> 中的内容。
因此绝大部分情况下请将脚本放在 <body> 的底部,也就是 </body> 出现之前。如下:
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>示例</title>
		<!--样式表-->
		<link rel="stylesheet" type="text/css" href="style.css">
	</head>
	<body>
		<!--网页主体-->
		<p>Hello, world!</p>
		...
		...
		...

		<!--脚本-->
		<script type="text/javascript" src="script.js"></script>
	</body>
</html>

1.2 合并脚本

一个网站通常需要多个 JavaScript 文件,考虑到 HTTP 请求的开销,下载单个 100 KB 的文件要比下载四个 25 KB 的文件更快。
如果你的网站用到了过多的脚本,那么合并它们吧。看看雅虎怎么做:
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.7.0/build/yahoo/yahoo-min.js&2.7.0/build/event/event-min.js"></script>

1.3 无阻塞脚本

为了创建快速响应的 Web 应用,我们精简代码,合并脚本只产生一次请求,把脚本放在 <body> 底部加载,但仍无法改变脚本的执行会锁死浏览器一段时间这一事 实。为了避免这种问题,可以在页面加载完毕以后才加载 JavaScript 代码,即在 window 的 load 事件触发以后再下载脚本。

1.3.1 延迟脚本

给 <script> 标签加一个 defer 属性,告诉浏览器请下载该脚本文件,但不要立即执行它,当网页加载完毕后(但会在 onload 事件触发前)执行代码。如下:

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>示例</title>
	</head>
	<body>
		<script type="text/javascript" defer> alert('defer'); </script>
		<script type="text/javascript"> alert('script'); </script>
		<script type="text/javascript"> window.onload = function() { alert('load'); }; </script>
	</body>
</html>
不支持 defer 属性的浏览器弹出顺序为 defer、script、load。而支持 defer 属性的浏览器弹出的顺序为 script、defer、load。
defer 属性的兼容性不好,旧的浏览器和移动设备上兼容性不佳,不过没关系,接下来还有别的解决方案。

1.3.2 动态脚本元素

通过 DOM API 可以用 JavaScript 动态创建 HTML 中的所有元素,包括 <script> 元素。于是,你可以这样加载 JavaScript 脚本:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'script.js';
document.head.appendChild(script); // HTML 5 支持,可以使用 docuent.getElementsByTagName('head')[0] 代替
这样加载的好处在于:无论何时启动下载,文件的下载和执行过程都不会阻塞页面其他进程。即便将代码放在 <head> 里面也不影响页面,而且推荐将动态生成的 <script> 元素插入到 <head> 中,因为当 <body> 中的内容没有全部完全加载完成时,IE 可能会抛出一个错误。

jQuery 的 $.Ajax() 函数支持回调,回调是个好东西,可以做很多事情。我们想写一个 loadScript(url, callback) 函数,其中的 callback 参数是我们感兴趣的,执行这个 callback 的关键是确定动态脚本元素何时被加载完成,下面给出这个函数:

// 函数定义
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 { // 其他浏览器
		script.onload = function() {
			callback();
		};
	}

	script.src = url;
	document.getElementsByTagName('head')[0].appendChild(script);
}

// 使用 loadScript 函数
loadScript('script.js', function() {
	alert('load successfully');
});

1.3.3 Ajax 请求脚本

// 不完善的实现
var xhr = new XMLHttpRequest();
xhr.open('get', 'script.js', true);
xhr.onreadystatechange = function() {
	if(xhr.readyState == 4) {
		if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
			var script = document.createElement('script');
			script.type = 'text/javascript';
			script.text = xhr.responseText;
			document.body.appendChild(script);
		}
	}
}
不推荐这种方式,因为浏览器的同源策略限制了 xhr 的跨域请求,大型网站的一些静态资源都缓存在 CDN 上面,xhr 请求不到这上面的资源,还要做特殊处理。

loadScript 函数是推荐的方式,具体组织方式看你的习惯。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值