高性能js--加载和运行
浏览器是如何加载js的?
当浏览器遇到一个<script>标签的时候,浏览器首先根据标签的scr属性下载js代码,然后运行js代码,继而继续解析和翻译页面,浏览器在遇到<body>标签之前是不会渲染任何部分的,如果此时<head>中需要加载的js文件很多很大的话,页面则会加载很慢,用户可能看到的页面就是一个白板,影响页面的交互!
Internet Explorer 8, Firefox 3.5, Safari 4, 和Chrome 2允许并行下载js文件,加快了js的下载时间,但是浏览器支持并行下载的数量有限制,一旦并行下载数量超过浏览器允许的数量,还是会堵塞其他资源的下载。
解决方案:
1.将脚本放在页面底部
一种常见的做法就是将<script>标签放在闭合的</body>之前,这样就可以先把页面展示给用户,让页面加载的速度显示不是很慢,这时最好将css文件放在head中,一遍加载DOM一遍渲染样式。
2.成组下载脚本
多个http请求也会降低页面性能,为了提高性能,我们可以将多个脚本文件放到一个文件中下载,这虽然减少了http请求,但是每次发布之前都要合并文件,并不是很好的解决方法,为此,我们可以采用成组的下载方式来达到目的,成组下载就是一次请求多个脚本文件。例如:
http:www.3c.com/ss.ss?file1.js&file2.js...
每次向服务器的固定服务请求下载多个文件,服务器将多个文件合并到一起返回给客户端,这是html页面包含多个外部js的最佳方法。
3.延时加载
如果js文件又大又多,那么无论我们怎么压缩文件减少http请求数,js的加载都会占用一定的时间,这时比较好的方法是等页面加载完成后再加载js,也就是在window.onload事件发出之后开始下载代码。
延迟加载的一个通用做法是动态的创建脚本元素,一个新的<script>元素可以非常容易的通过DOM函数创建:
var script = document.createElement("script");
script.type="text/javascript";
script.src="***.js";
document.getElementByTagName("head")[0].appendChild(script);
当script元素被添加到页面之后便开始下载脚本文件。这样无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程,当js文件下载完成后,返回的代码通常被立即执行(除了FF和Opera,她们将待此前的所有动态脚本节点执行完毕)
当动态加载的script只是其他script调用的接口时,就会出现问题,因为调用代码不知道被调用的接口是否已加载完毕,还好目前的主流浏览器都能够跟踪节点是否加载完毕!
FF, Opera, Chrome和Safari3+会在节点接收完成后发出一个load事件;IE则是发出一个readystatechange事件,<script>元素有一个readyState属性,它的值随着下载过程而改变。readyState有5种取值:uninitialized(默认状态),loading(下载开始),loaded(下载完成),interactive(下载完成但尚不可用),complete(所有数据已准备好)。微软文档上说,这些取值不一定全部出现,有时script会得到loaded不出现complete,有时script会得到complete不出现loaded。最安全的做法就是,在readystatechange事件中检查这两种状态,当出现两种状态之一时,删除readystatechange句柄,以避免事件不会被执行两次。
代码如下所示:
function loadScript(url, callback) {
var script = document.createElement("script");
script.type = "text/javascript";
if (script.readyState) {
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);
};
如果要加载多个文件,并且要保证顺序,则可以采用将上述函数串联的方式实现。
动态脚本加载是最常用的JavaScript非阻塞下载方式,因为它跨浏览器而且简单易用。