JavaScript执行效率优化和内存管理优化.docx
- 文档编号:6867959
- 上传时间:2023-01-11
- 格式:DOCX
- 页数:12
- 大小:19.22KB
JavaScript执行效率优化和内存管理优化.docx
《JavaScript执行效率优化和内存管理优化.docx》由会员分享,可在线阅读,更多相关《JavaScript执行效率优化和内存管理优化.docx(12页珍藏版)》请在冰豆网上搜索。
JavaScript执行效率优化和内存管理优化
JS执行效率及内存管理
1执行效率
1.1DOM
1.1.1使用DocumentFragment优化多次append
说明:
添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。
该做法可以减少页面渲染dom元素的次数。
经IE和Fx下测试,在append1000个元素时,效率能提高10%-30%,Fx下提升较为明显。
优化前:
for(vari=0;i<1000;i++){
varel=document.createElement('p');
el.innerHTML=i;
document.body.appendChild(el);
}
优化后:
varfrag=document.createDocumentFragment();
for(vari=0;i<1000;i++){
varel=document.createElement('p');
el.innerHTML=i;
frag.appendChild(el);
}
document.body.appendChild(frag);
1.1.2通过模板元素clone,替代createElement
说明:
通过一个模板dom对象cloneNode,效率比直接创建element高。
性能提高不明显,约为10%左右。
在低于100个元素create和append操作时,没有优势。
优化前:
varfrag=document.createDocumentFragment();
for(vari=0;i<1000;i++){
varel=document.createElement('p');
el.innerHTML=i;
frag.appendChild(el);
}
document.body.appendChild(frag);
优化后:
varfrag=document.createDocumentFragment();
varpEl=document.getElementsByTagName('p')[0];
for(vari=0;i<1000;i++){
varel=pEl.cloneNode(false);
el.innerHTML=i;
frag.appendChild(el);
}
document.body.appendChild(frag);
1.1.3使用一次innerHTML赋值代替构建dom元素
说明:
根据数据构建列表样式的时候,使用设置列表容器innerHTML的方式,比构建dom元素并append到页面中的方式,效率有数量级上的提高。
优化前:
varfrag=document.createDocumentFragment();
for(vari=0;i<1000;i++){
varel=document.createElement('p');
el.innerHTML=i;
frag.appendChild(el);
}
document.body.appendChild(frag);
优化后:
varhtml=[];
for(vari=0;i<1000;i++){
html.push('
'+i+'
');}
document.body.innerHTML=html.join('');
1.1.4使用firstChild和nextSibling代替childNodes遍历dom元素
说明:
约能获得30%-50%的性能提高。
逆向遍历时使用lastChild和previousSibling。
优化前:
varnodes=element.childNodes;
for(vari=0,l=nodes.length;i varnode=nodes; …… } 优化后: varnode=element.firstChild; while(node){ …… node=node.nextSibling; } 1.2字符串 1.2.1使用Array做为StringBuffer,代替字符串拼接的操作 说明: IE在对字符串拼接的时候,会创建临时的String对象;经测试,在IE下,当拼接的字符串越来越大时,运行效率会急剧下降。 Fx和Opera都对字符串拼接操作进行了优化;经测试,在Fx下,使用Array的join方式执行时间约为直接字符串拼接的1.4倍。 优化前: varnow=newDate(); varstr=''; for(vari=0;i<10000;i++){ str+='123456789123456789'; } alert(newDate()-now); 优化后: varnow=newDate(); varstrBuffer=[]; for(vari=0;i<10000;i++){ strBuffer.push('123456789123456789'); } varstr=strBuffer.join(''); alert(newDate()-now); 1.3循环语句 1.3.1将循环控制量保存到局部变量 说明: 对数组和列表对象的遍历时,提前将length保存到局部变量中,避免在循环的每一步重复取值。 优化前: varlist=document.getElementsByTagName('p'); for(vari=0;i …… } 优化后: varlist=document.getElementsByTagName('p'); for(vari=0,l=list.length;i …… } 1.3.2顺序无关的遍历时,用while替代for 说明: 该方法可以减少局部变量的使用。 比起效率优化,更能直接看到的是字符数量的优化。 该做法有程序员强迫症的嫌疑(==! )。 优化前: vararr=[1,2,3,4,5,6,7]; varsum=0; for(vari=0,l=arr.length;i sum+=arr; } 优化后: vararr=[1,2,3,4,5,6,7]; varsum=0,l=arr.length; while(l--){ sum+=arr[l]; } 1.4条件分支 1.4.1将条件分支,按可能性顺序从高到低排列 说明: 可以减少解释器对条件的探测次数。 1.4.2在同一条件子的多(>2)条件分支时,使用switch优于if 说明: switch分支选择的效率高于if,在IE下尤为明显。 4分支的测试,IE下switch的执行时间约为if的一半。 1.4.3使用三目运算符替代条件分支 优化前: if(a>b){ num=a; }else{ num=b; } 优化后: num=a>b? a: b; 1.5定时器 1.5.1需要不断执行的时候,优先考虑使用setInterval 说明: setTimeout每一次都会初始化一个定时器。 setInterval只会在开始的时候初始化一个定时器 优化前: vartimeoutTimes=0; functiontimeout(){ timeoutTimes++; if(timeoutTimes<10){ setTimeout(timeout,10); } } timeout(); 优化后: varintervalTimes=0; functioninterval(){ intervalTimes++; if(intervalTimes>=10){ clearInterval(interv); } } varinterv=setInterval(interval,10); 1.5.2使用function而不是string 说明: 如果把字符串作为setTimeout和setInterval的参数,浏览器会先用这个字符串构建一个function。 优化前: varnum=0; setTimeout('num++',10); 优化后: varnum=0; functionaddNum(){ num++; } setTimeout(addNum,10); 1.6其他 1.6.1尽量不使用动态语法元素 说明: eval、Function、execScript等语句会再次使用javascript解析引擎进行解析,需要消耗大量的执行时间。 1.6.2重复使用的调用结果,事先保存到局部变量 说明: 避免多次取值的调用开销。 优化前: varh1=element1.clientHeight+num1; varh2=element1.clientHeight+num2; 优化后: vareleHeight=element1.clientHeight; varh1=eleHeight+num1; varh2=eleHeight+num2; 1.6.3使用直接量 说明: vara=newArray(param,param,...)->vara=[] varfoo=newObject()->varfoo={} varreg=newRegExp()->varreg=/.../ 1.6.4避免使用with 说明: with虽然可以缩短代码量,但是会在运行时构造一个新的scope。 OperaDev上还有这样的解释,使用with语句会使得解释器无法在语法解析阶段对代码进行优化。 对此说法,无法验证。 优化前: with(a.b.c.d){ property1=1; property2=2; } 优化后: varobj=a.b.c.d; obj.property1=1; obj.property2=2; 1.6.5巧用||和&&布尔运算符 优化前: functioneventHandler(e){ if(! e)e=window.event; } 优化后: functioneventHandler(e){ e=e||window.event; } 优化前: if(myobj){ doSomething(myobj); } 优化后: myobj&&doSomething(myobj); 1.6.6类型转换 说明: 1). 数字转换成字符串,应用""+1,性能上: (""+)>String()>.toString()>newString(); 2). 浮点数转换成整型,不使用parseInt(),parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用Math.floor()或者Math.round() 3). 对于自定义的对象,推荐显式调用toString()。 内部操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String。 1.6.7多用id,少用class JS在IE浏览器下的效率并不好,尤其当页面很大且具有繁杂的逻辑操作时 在写html时,如果使用id,JS会很快在一次遍历中找到需要的元素(无论有几个id它都会在找到第一个id后返回)。 而通过class等去寻找,程序会在整个文档中一遍又一遍的去遍历,找到一个比较判断以后再去找第二个第三个……非常浪费资源。 2内存管理 2.1循环引用 说明: 如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。 内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。 简单的循环引用: varel=document.getElementById('MyElement'); varfunc=function(){…} el.func=func; func.element=el; 但是通常不会出现这种情况。 通常循环引用发生在为dom元素添加闭包作为expendo的时候。 如: functioninit(){ varel=document.getElementById('MyElement'); el.onclick=function(){……} } init(); init在执行的时候,当前上下文我们叫做context。 这个时候,context引用了el,el引用了function,function引用了context。 这时候形成了一个循环引用。 下面2种方法可以解决循环引用: 2.1.1 置空dom对象 优化前: functioninit(){ varel=document.getElementById('MyElement'); el.onclick=function(){……} } init(); 优化后: functioninit(){ varel=document.getElementById('MyElement'); el.onclick=function(){……} el=null; } init(); 将el置空,context中不包含对dom对象的引用,从而打断循环应用。 如果我们需要将dom对象返回,可以用如下方法: 优化前: functioninit(){ varel=document.getElementById('MyElement'); el.onclick=function(){……} returnel; } init(); 优化后: functioninit(){ varel=document.getElementById('MyElement'); el.onclick=function(){……} try{ returnel; }finally{ el=null; } } init(); 2.1.2构造新的context 优化前: functioninit(){ varel=document.getElementById('MyElement'); el.onclick=function(){……} } init(); 优化后: functionelClickHandler(){……} functioninit(){ varel=document.getElementById('MyElement'); el.onclick=elClickHandler; } init(); 把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。 2.2通过javascript创建的dom对象,必须append到页面中 说明: IE下,脚本创建的dom对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的! 示例代码: functioncreate(){ vargc=document.getElementById('GC'); for(vari=0;i<5000;i++) { varel=document.createElement('div'); el.innerHTML="test"; //下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化 gc.appendChild(el); } } 2.3释放dom元素占用的内存 说明: 将dom元素的innerHTML设置为空字符串,可以释放其子元素占用的内存。 在rich应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的dom元素使用的内存。 2.4释放javascript对象 说明: 在rich应用中,随着实例化对象数量的增加,内存消耗会越来越大。 所以应当及时释放对对象的引用,让GC能够回收这些内存控件。 对象: obj=null 对象属性: deleteobj.myproperty 数组item: 使用数组的splice方法释放数组中不用的item 2.5避免string的隐式装箱 说明: 对string的方法调用,比如'xxx'.length,浏览器会进行一个隐式的装箱操作,将字符串先转换成一个String对象。 推荐对声明有可能使用String实例方法的字符串时,采用如下写法: varmyString=newString('HelloWorld');
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JavaScript 执行 效率 优化 内存 管理