高性能javascript
1、加载与执行
由于多数浏览器使用单一线程来处理用户UI刷新和javascript脚本执行,所以同一时刻只能做一件事。这样就告诉我们js执行时间过程越久,浏览器等待响应的时间就越长,这里就存在一个性能问题,就是脚本的位置问题。
由于脚本会阻塞页面渲染,所以只有js全部下载并且执行完成后才会渲染页面,那么我们期望js不要在页面渲染的时候进行加载。因此我们推荐的方式是:
所有script标签尽可能的放到body标签的底部,以尽量减少对整个页面下载的影响。
1、动态脚本元素
var script = document.createElement('script'); script.type = 'text/javascript'; script.onload = function(){//非IE alert('script loaded'); }; script.onreadystatechange = function(){//IE if(script.readyState == 'loaded' || script.readyState == 'complete'){ script.onreadystatechange = null; alert('script loaded'); } }; script.src = 'file1.js'; document.getElementsByTagName('head')[0].appendChild(script);
onreadystatechange 有五个值:如下
uninitialized |
初始状态 |
loading |
开始下载 |
loaded |
下载完成 |
interactive |
数据完成下载但尚不可用 |
complete |
所有数据已准备就绪 |
动态加载脚本的兼容性写法
function loadScript(url,callback){ var script = document.createElement('script'); script.type = 'text/javascript'; if(script.readyState){//IE if(script.readyState == 'loaded' || script.readyState == 'complete'){ script.onreadystatechange = null; callback(); } }else{ script.onload = function(){//非IE callback(); }; } script.src = url; document.getElementsByTagName('head')[0].appendChild(script); }
使用方法如下:
loadScript('file1.js',function(){
alert('file is loaded!');
});
loadScript('file1.js',function(){
loadScript('file2.js',function(){
loadScript('file3.js',function(){
alert('all files are loaded!');
});
});
});
XMLHttpRequest 脚本注入
var xhr = new XMLHttpRequest(); xhr.open('get','file1.js',true); xhr.onreadystatechange = function(){ if(readyState == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ var script = document.createElement('script'); script.type = 'text/javascript'; script.src = xhr.responseText; document.body.appendChild(script); } } }
通过get请求一个js文件。 http状态码 2xx表示有效响应,304表示从缓存读取
缺点是该代码不支持跨域,针对走cdn的文件不能采用这个方法
动态加载js的通用工具可以在下面地址获取
https://github.com/rgrove/lazyload/
使用方法如下:
LazyLoad.js('file1.js',function(){
alert('file is loaded');
});
//按顺序加载多个文件
LazyLoad.js(['1.js','2.js'],function(){
alert('file is loaded');
});
第二种
LABjs
http://labjs.com/
用法举例
$LAB.script('file.js').wait(function(){
//初始化
});
//lab script方法用来下载文件,wait方法用来指定文件下载并执行完毕后所调用的函数。支持链式调用
$LAB.script('1.js')
.script('2.js')
.wait(function(){
//初始化
});
前面的举例中1.js不一定会保证在2.js前调用。要保证这一点可以这么写
$LAB.script('1.js').wait()
.script('2.js')
.wait(function(){
//初始化
});
以上都是比较好的动态加载js的方式,且不会阻塞浏览器!
例子和说明参考来自《高性能javascript》第一章
事件委托
当页面中存在大量元素的时候,要为每个元素绑定一个或多个事件处理程序,这种情况可能会影响性能!每绑定一次事件处理程序都是有代价的,它加重了页面的负担,增加了运行期间的执行时间。
那么一个好的事件处理程序的技术是事件委托。它基于这样一个事实:事件是逐层向上冒泡并能被父元素捕获。使用事件代理只需给父元素绑定一个事件处理程序,就可以处理其子元素上触发的所有的事件。
在IE下不支持捕获,但是只要支持冒泡就足够了!
例如下面的例子:
document.getElementById('main').onclick = function(e){
e = e || window.event;
var target = e.target || e.srcElement;
var pageId,hrefparts;
if(target.nodeName !== 'A'){
return ;
}
hrefparts = target.href.split('/');
pageId = hrefparts[hrefparts.length-1];
pageId = pageId.replace('.html','');
var xhr = new XMLHttpRequest();
xhr.open('get','page.php?page='+pageId,true);
xhr.onreadystatechange = function(){
if(readyState == 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
//更新页面
}
}
}
if(typeof e.preventDefault === 'function'){
e.prenentDefault();
e.stopPropagation();
}else{
e.returnValue = false;
e.canceBubble = true;
}
}
事件委托并不难,你只需要检查事件是否来自你所预期的元素,然后根据预期的元素来执行相应元素所绑定的事件处理程序。

浙公网安备 33010602011771号