高性能Javascript【一】加载和执行

【本文系外部转载,原文地址: http://www.hotels2map.com/blog/?p=109】
最近看《高性能Javascript》一书,发现以前一些零散的知识在这里都被串在一起了,有些东西令人觉得相见恨晚,于是打算写东西记录一下,希望能够坚持写完。多谢laser的小图书馆和kaiye的书:)。

Javascript代码具有阻塞特性:当页面在加载或者执行Javascript代码的时候(遇到<script>标签,不管是内嵌还是外链),页面其他部分的加载、渲染和用户交互都会停止。因为Javascript代码执行过程中有可能会改变页面的内容(比如document.write),而浏览器只有一个进程用来同时处理用户界面(UI)更新和Javascript的执行,所以浏览器会先等Javascript执行完成之后,再继续解析和渲染页面的其他部分。因此,加载和执行的优化,主要是如何解决页面阻塞问题:

1、脚本在页面的位置:

将所有的<script>标签放到页面的底部,靠近</body>标签,这能确保在脚本执行前页面已经完成了渲染;尽量不把脚本放在<head>标签中,避免内容没有加载之前,页面被脚本阻塞,导致页面在某个时间段内一篇空白。

2、组织脚本

合并文件,减少面中的<script>标签,下载一个100k的脚本文件,比下载4个25k的脚本文件更快,而且能够减少页面被阻塞的次数。

3、无阻塞脚本:

a)延迟脚本执行

使用<script>标签的defer属性(适用于外链脚本文件,仅适用于IE、Firefox 3.5以上、chrome最新版本)。

<script type="text/javascript" src="a.js" defer="defer"></script>
https://developer.mozilla.org/En/HTML/Element/Script

b)动态创建<script>标签

这样添加的脚本会在加载玩之后立即自动执行,可以添加回调函数,在需要的时候执行脚本,需要注意的是ie的回调中readyState的判断和处理。

function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){  //IE
script.onreadystatechange = function(){
//ie下readyState的状态的值loaded和complete可能只会出现一个
if (script.readyState == "loaded" || script.readyState == "complete"){
//避免loaded和complete重复处理
script.onreadystatechange = null;
callback();
}
};
} else {  //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}

c)XMLHttpRequest脚本注入(ajax)

下载之后不会立即自动执行,但是不能跨域。

推荐方案:

动态创建<script>标签的方法loadScript。

也可以参考YUI3、Lazyload、LABjs的做法。

YUI3:http://developer.yahoo.com/yui/3/yui/

通过use来动态加载各种已经定义好的文件

YUI().use('animation', function(Y) {
// Y.Anim is available
});

Lazyload:https://github.com/rgrove/lazyload

可以同时加载多个,并按照顺序执行:

LazyLoad.js(['foo.js', 'bar.js', 'baz.js'], function () {
alert('all files have been loaded');
});
// Load a CSS file and pass an argument to the callback function.
LazyLoad.css('foo.css', function (arg) {
alert(arg);
}, 'foo.css has been loaded');

LABjs:http://labjs.com/

支持链式操作,wait处理依赖或执行先后关系。

<script>
$LAB
.script("framework.js").wait()
.script("plugin.framework.js")
.script("myplugin.framework.js").wait()
.script("init.js").wait();
</script>

tips

  1. 不要把内嵌的脚本放在link进来的样式文件之后,这样脚本会等待样式文件下载完之后,页面获取了精确的样式信息,再执行脚本。
  2. 创建<script>标签添加到head比body更安全,因为在body部分添加script时,script中的脚本可能会对body进行操作,而body还没有加载完,会出现”操作已终止”的错误。http://www.nczonline.net/blog/2008/03/17/the-dreaded-operation-aborted-error/
  3. 虽然书上说Lazyload用来加载Css文件没多大意义,但是,其中的回调函数有妙用,因为有些时候我们需要在css文件加载完成之后再进行某些操作。

你可能感兴趣的:(高性能Javascript【一】加载和执行)