自述:谷歌的v8内核确实厉害,所以现在网页的运算速度极大的提升并且几乎大部分的网页代码不需要很深入的优化,就能够让网页流畅的运行起来,但是代码优化真的不需要了么?可能突破自己的瓶颈就差这一步。
一、加载与执行
- 解析多个
<script>
标签中间需要间隔的时间 <script>
文件要先加载完毕才能去渲染页面的内容,所以通常的做法是将<script>
标签放在body
标签的底部- 尽量去压缩CSS与JS的代码,能够节省很多的加载时间
- 动态脚本的加载,是最通用的无阻塞加载解决方式(关于动态加载的方式这里的博客已经阐述的很清楚了)
例:
<html>
<head>
<title></title>
<script type="text/javascript">
function init()
{
var myScript= document.createElement("script");
myScript.type = "text/javascript";
myScript.appendChild(document.createTextNode("function functionOne(){alert(\"加载\"); }"));
document.body.appendChild(myScript);
}
</script>
</head>
<body>
<input type="button" value="测试按钮" onclick="init()"/>
</body>
</html>
二、数据存储
- 自变量只代表自身,不存储在特定的位置,例:字符串、数字、布尔值等
- 本地的变量,例:var、let、const
- 数据元素与对象成员
- 通常来说,字面量和局部变量的访问速度会快于数据项和对象成员的访问速度
- 函数读写局部变量总是最快的,而读取全局变量是最慢的,因为全局变量总是存在于执行环境作用域链的最末端
注:如果某个跨作用域的值在函数中被引用一次以上,那么建议把他存储到局部变量里;
function int()
{
var bd=document.body,
links=document.getElementById("a");
document.getElementById("go").onclick=function(){/*处理语句*/}
}
该函数引用了三次document
,而document
是全局变量,我们可以先将全局变量的引用存储在一个局部变量中,用来替代全局变量,优化如下:
function int()
{
var doc=document,
bd=doc.body,
links=doc.getElementById("a");
doc.getElementById("go").onclick=function(){/*处理语句*/}
}
经过修改,访问全局变量的次数减少为1次,虽然简单的函数对于速度的提升并不明显,但是在几十个全局变量一直反复调用的页面里,改善将十分显著。
try
与catch
语句也会改变作用域链,建议在catch语句中调用处理函数而不是直接在书写错误处理语句。- 缓存对象成员的值,在同一个函数中没有必要多次的读取同一个对象成员。
例:
return Element.className==className1||Element.className==className2;
在以上的代码中 Element.className
被调用了两次,就需要定义一个变量来存储它,然后再用变量去调用,与第二点类似。
注:这种方法不推荐用在对象的成员方法上,因为会把this指向Window,从而导致自己的代码解析出错。
三、DOM编程
把Dom与JavaScript各自想象成一个岛屿,他们之间有一座大桥,经过的时候需要收取过桥费,访问Dom的次数越多收取的过桥费就越高,而修改Dom元素的费用则更昂贵。
例:
function(){
for(var i=0;i<15000;i++)
{
document.getElentById("name").innerHTML+='a';
}
}
每次循环迭代,该元素就都要访问两次元素:一次读取、一次重写,我们应该用局部变量存储修改中的内容,在循环结束之后一次性写入 (在IE中以下写法比第一种快155
倍)。
function(){
var content=" ";
for(var i=0;i<15000;i++)
{
content+="a";
}
document.getElentById("name").innerHTML+=content;
}
innerHTML
与document.createElement()
的原声Dom方法比较
结果:相差无几,在IE6中innerHTML要快,在最新的Webkit内核浏览器中innerHTML则会更慢。- HTML集合
document.getElementsByName/className/TagName()
等api返回的是一个带有length属性的集合而不是数组,而读取一个集合的length时间要比读取数组更久。
例:
var coll=document.getElementsByTagName("div");
function init(){
for(var count=0;count<coll.length;count++)
{
//处理语句
}
}
我们可以看到,在进行判断的时候需要引发集合的更新来判断length的值,所以可以进行如下优化:
function init(){
var coll=document.getElementsByTagName("div"),
len=coll.length;
for(var count=0;count<len;count++)
{
//处理语句
}
}
- 选择器多使用:
querySelector
与querySelectorAll()
; - 浏览器的重绘与重排
两个都是昂贵的操作,比如改变元素的宽高,可能会同事影响到其它的元素的位置,浏览器进行重新计算渲染,这个是"重排",计算之后收到影响的元素会重新绘制到屏幕中,这是"重绘"。
- 包括:
offsetTop/Left/Width/Height
,scrollTop/Left/Width/Height
,clientTop/Left/Width/Height
等。 - 以上的属性方法需要重新返回最新的布局信息,都在偷偷的把全部内容进行重排,需要多注意使用,不能滥用。
- 大量的
:hover
伪类也会降低响应速度
例:在一个有1000行表格中就不要用:hover
来改变背景色,cpu的运算率会增加到80%~90%
四、算法
- 循环:在for、while、do-while、for-in中for-in的速度是最慢的,但是需要用他来迭代一个属性数量未知的对象。
- 减少迭代的工作工作量
例:
for(var i=0;i<item.length;i++){}
修改为以下方式在IE中可以节省25%-50%的时间;
for(var i=0,len<item.length=;i<len;i++){}
我们还可以使用倒序的方式,这样就只与0比较,节省出50%-60%的时间;
for(var len=item.length<len;len--){}
- if-else与switch
- 通常条件数量越大switch更易读,但是看个人与团队的情况。
- 优化if-else:最简单的优化方法是确保最可能出现的条件放在首位置。
五、编程
- 避免双重求值如:
setTimeout("sum=sum1+sum2",1000);
//或
setInterval("sum=sum1+sum2",1000);
这种情况下,就应该把厘米的语句通过函数去调用而不是直接写出来。
2. 网页图片进行懒加载工作。
3. 多使用原生的运算,math()的api浏览器中已经使用低级语言写好了,会比自己去计算快很多。