您的位置:首页 > Web前端 > JavaScript

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

2014-05-04 15:19 561 查看

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 函数是推荐的方式,具体组织方式看你的习惯。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: