1、无论当前的js代码是内嵌还是包含在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成,在这个过程中渲染和用户交互是完全被阻塞的。
2、现在浏览器允许script标签允许并行下载JS文件但其他资源下载时仍会阻塞。
3、因为每个script标签初始化下载时会阻塞页面渲染,所以要尽量减少script标签的数量并将脚本放在body标签结束前。
如:
<script type="text/javascript" src="https://lpzz.me?xxx1.js&xxx2.js"></script>
4、尽管单个较大的js文件只产生一次http请求,却会死锁浏览器一大段时间,所以要向页面逐步加载js文件,defer同步确保执行顺序【async异步执行,非按顺序】
如:
<script type="text/javascript" src="xxx1.js" defer></script>
5、动态脚本元素无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。
var script=document.creatElement("script");
script.type="text/javascript";
script.src="xxx.js";
document.getElementByTagName("head")[0].appendChild(script);
兼容写法:
//url:js文件;callback:完成加载后的回调函数
function loadScript(url,callback){
var script=document.createElement("script");
script.type="text/javascript";
if(script.readyState){
script.onreadstatechange=function(){
if(script.readyState=="loaded"||script.readyState=="complete"){
script.onreadystatechange=null;
callback();
}
};
}else{
script.onload=function(){
calllback();
};
}
script.src=url;
document.getElementsByTagName("head")[0].appendChild(script);
}
//如:确保加载顺序
loadScript("xxx1.js",function(){
loadScript("xxx2.js",function(){
loadScript("xxx3.js",function(){
alert("全部加载完毕!");
});
});
});
6、XHR【XMLHttpRequest】对象也可以获取脚本并注入页面,可以下载但不立即执行,但文件须与请求的页面出于相同的域,不能从CDN下载,大型web应用通常不采用此技术。
7、大量添加js代码时推荐无阻塞模式做法:先添加动态加载所需要的代码,尽量精简,再加载初始化页面所需要的剩下的代码。
8、尽量使用字面变量和局部变量,减少数组项和对象成员的使用。
9、在执行环境的作用域链中,一个标识符所存的位置越深,读写速度越慢,如果某个跨作用域的值在函数中被引用一次以上,就考虑把它存在局部变量里。
10、with语句,try-catch中的catch子句和包含eval的函数都被认为是动态作用域,无法通过静态分析检测出来,经过优化的js引擎,尝试通过分析代码来确定哪些变量可以在特定时候被访问,但当涉及动态作用域时,这种优化方式就失效了。
11、使用闭包可能导致性能问题。
12、js中的对象是基于原型的,一旦创建了一个内置对象的实例,就会拥有一个Object实例作为原型,即对象有两种成员类型:实例成员和原型对象。原型链中位置越深,找到它越慢,性能消耗越大。
13、点操作符越多,嵌套越深,读取也越慢。不要在同一个函数中查找同一个对象成员,除非它的值改变了。
14、DOM天生就慢,运算尽量不要放在这一部分,如:
//优化前:
function innerHTMLLoop(){
for(var count = 0; count < 15000; count++){
document.getElementById('here').innerHTML += 'a';
}
}
//优化后:
function innerHTMLLoop2(){
var content = ' ';
for(var count = 0; count < 15000; count++){
content +='a';
}
document.getElementById('here').innerHTML += content;
}
15、在对性能有苛刻要求时一般使用innerHTML而不是DOM方法,但大多数日常操作相差不大。
//使用innerHTML生成1000行2列的表格,第一列显示行数,第二列奇列显示yes偶列显示no
function tableTnnerHTML(){
var i,h=['<table border="1" width="100%">'];
h.push('<thead>');
h.push('<tr><th>id<\/th><th>yes?<\/th><\/tr>');
h.push('<\/thead>');
h.push('<tbody>');
for(var i=1;i<=1000;i++){
h.push('<tr><td>');
h.pust(i);
h.push('<\/td><td>');
h.push(i%2?'yes':'no');//有余数是yes,没余数是no
h.push('<\/td>');
h.push('<\/tr>');
}
h.push('<\/tbody>');
h.push('<\/table>');
documentElementById('here').innerHTML=h.join('');
};
//使用DOM方法生成1000行2列的表格,第一列是一个以i命名的链接,第二列是一个链接列表
function tableDOM(){
var i,table,thead,tbody,tr,th,td,a,ul,li;
thead=document.createElement('thead');
tr=document.createElement('tr');
th=document.createElement('th');
th.appendChild(document.createTextNode('URL'));
tr.appendChild(th);//
th=document.createElement('th');
th.appendChild(document.createTextNode('ACTION'));
tr.appendChild(th);//
thead.appendChild(tr);
tbody=document.createElement('tbody');
for(i=1;i<=1000;i++){
tr=document.createElement('tr');
a=document.createElement('a');
a.setAttribute('href','https://lpzz.me/'+i+'.html');
a.appendChild(document.createTextNode('https://lpzz.me/'+i+'.html'));
td=document.createElement('td');
td.appendChild(a);
tr.appendChild(td);
ul=document.createElement('ul');
a=document.createElement('a');
a.setAttribute('href','https://lpzz.me/edit.html?id='+i);
a.appendChild(document.createTextNode('edit'));
li=document.createElement('li');
li.appendChild(a);
ul.appendChild(li);
a=document.createElement('a');
a.setAttribute('href','https://lpzz.me/delete.html?id='+i);
a.appendChild(document.createTextNode('delete'));
li=document.createElement('li');
li.appendChild(a);
ul.appendChild(li);
td=document.createElement('td');
td.appendChild(ul);
tr.appendChild(td);
tbody.apppendChild(tr);
}
table=document.createElement('table');
table.setAttribute('border',1);
table.setAttribute('width','100%');
table.appendChild(thead);
table.appendChild(tbody);
document.getElementById('here').appendChild(table);
};
16、DOM更新还可以采用节点克隆的方法,e.cloneNode()而不是document.createElement()。
17、HTML集合包括document.image/links/forms/forms[0]【第一个表单】以及document.getElementsByName('')/getElementsByClassName('')/getElementsByTagName('')/getElementsByName('')。在需要对同一个集合多次遍历操作时,建议将一个集合复制到一个数组,并使用局部变量存储集合属性。同时,nextSibling【返回相邻元素】在某些条件下要比childNodes【返回集合】快。
//nextSubling
function testNextSubling(){
var e=document.getElementById('mydiv'),
ch=e.firstChild,
name='';
do{
name=ch.nodeName;
}while(ch=ch.nextSibling);
return name;
};
//childNodes
function testChildNodes(){
var e=document.getElementById('mydiv'),
ch=e.childNodes,
len=ch.length,//务必缓存属性,防止迭代更新
name='';
for(var count=0;count<len;count++){
name=ch[count].nodeName;
}
return name;
};
18、使用CSS选择器来定位节点,如:document.querySelectorAll("#menu a");或者document.querySelectorAll(".claname");
19、浏览器下载完页面所有的组件之后,会解析并生成两个内部数据结构,dom树【页面结构】渲染树【dom节点如何显示】,一旦两个树构建完成就开始绘制页面元素。当dom变化影响了元素的集合属性,浏览器会使渲染树受到影响的部分失效并重新构造渲染树【重排】,浏览器重新绘制受到影响的部分到屏幕【重绘】,所以要尽量减少这类过程的发生。
20、合并多次DOM对样式的修改,再一次性处理掉。
var e=documment.getElementById('mydiv');
e.style.cssText='border-left:1px;padding:5px;';//覆盖
e.style.cssText+=';border-right:1px;';
21、尽量减少布局信息的获取次数
22、不要大量使用:hover
23、多使用事件委托技术
24、元素属性值修改更新减少重排的优化方法。如:
var data=[
{
"url":"xx1.html",
"name":"xxx1"
},{
"url":"xx2.html",
"name":"xxx2"
}
];
//添加数据
function appendDataToElement(appendElement,data){
var a,li;
for(var i=0,max=data.length;i<max;i++){
a=document.createElement('a');
a.href=data[i].url;
a.appendChild(document.createTextNode(data[i].name));
li=document.createElement('li');
li.appendChild(a);
appendElement.appendChild(li);
}
};
//调用方法1
var ul=document.getElementById('mylist');
ul.style.display="none";
appendDataToElement(ul,data);
ul.style.display="block";
//调用方法2
var fragment=documment.createDocumentFragment();
appendDataToElement(fragment,data);
document.getElementById('mylist').appendChild(fragment);
//调用方法3
var old=document.getElementById('mylist');
var clone=old.cloneNode(true);
appendDataToElement(clone,data);
old.parentNode.replaceChild(clone,old);