标签存档: 性能优化

CSS优化

本文总结了一些CSS优化的规则,包括一些简写技巧,选择器的使用,及其它注意事项。

css简写技巧

1、属性值为0,而非0px。如果属性值为0,那么可以不为其添加单位(如px、em等),例如:

padding: 10px 5px 0px 0px;

 可以写成:

padding: 10px 5px 0 0;

2、背景属性合写。背景属性可能会包含设置背景色、背景图、背景图的位置和背景图重复方式的参数,可以将这些合并写到一句里,例如:

background-image: url(bg.png);
background-position: 0 0;
background-repeat: no-repeat;

可以写成:

background: url(bg.png) no-repeat 0 0;

4、文字属性合写。和背景一样,文字属性也有很多可能会用到的属性值,来个复杂的文字样式:

font-style:italic;
font-variant:small-caps;
font-weight:bold;
font-size:12px;
line-height:1.5;
font-family:Arial, sans-serif;

 可以写成:

font:italic small-caps bold 12px/1.5 Arial, sans-serif;

4、颜色简写。css里的颜色数值使用“#”加6个16进制数表示的。这6个数两个一组,分别表示red,green,blue的值,有人说如果每对的颜色值都是各自相等的,可以简写成一个数值。例如,#ff6600,可以简写成#f60。关于这写法没找到确实的数据证明对浏览器的渲染效率是否有影响,但十六进制的颜色值默认标准是大写字母及数字组成的六位数标注。在未知情况下不希望冒险而降低了渲染的效率,所以还是建议写成#FF6600。

5、margin、padding等的简写。有些人会这样声明边框:

margin-top:5px;
margin-right:10px;
margin-bottom:5px;
margin-left:10px;

可以这样简写:

margin:5px 10px 5px 10px;

css里,像margin、padding、border-width等在写属性值时都是按照上-右-下-左的顺时针方向来写的,不要弄混顺序。像上面的例子,上下边距,左右边距分别是相等的,还可以进一步简化:

margin:5px 10px;

同理,padding、border-width等也是如此。

6、border的简写。举个例子,声明一个1像素的黑色实线边框:

border-width:1px;
border-style:solid;
border-color:#000;

可以简写成:

border:1px solid #000;

有人可能会记不清顺序,我通常这样记,“数字靠两端,字母摆中间”。

7、列表样式。用的不多,一个例子:

list-style-type:square;
list-style-position:inside;
list-style-image:url(filename.gif);

这样简写:

list-style:square inside url(filename.gir);

选择器使用

据说Mozilla样式系统的选择器是从右向左匹配的,这里有篇文章https://developer.mozilla.org/en/Writing_Efficient_CSS,看看就行,毕竟因为ie6的存在,像>,+这样的选择器我们是用不到的,关于浏览器对选择器的支持情况,可以看下http://www.masterboke.cn/2009/02/26/css-browser-support/。不管选择器是从左还是从右匹配,有三点注意一下:

1、避免使用通用选择符。想*{},#test *{}这样的选择器还是不要用。

2、不要用标签修饰id选择器。不要出现div #test{}这样的选择器,id选择器直接单独使用就行,不用再画蛇添足。

3、不要使用标签修饰class选择器。不要出现div .test{}这样的选择器。

其它注意事项

1、对css代码进行压缩。不管开发时是啥样的,呈现到用户面前时必定是压缩过的。

2、应该将CSS 放置于结构的上方(一般放置于head 元素内)。CSS 是解释型语言,ff和ie在等待CSS 传输完成之前不会渲染任何东西。放在顶部,浏览器能够有针对性的对 HTML 页面从顶到下进行解析和渲染。

3、尽量使用 <link rel=”stylesheet” href=”http://www.masterboke.cn/test.css” type=”text/css”> 的样式导入方式,而减少@import 的使用,更不要使用多层嵌套的@import 。因为在 IE 里,@import 相当于将<link> 放在页面尾部。

4、不要使用css表达式。CSS Expressions这个东西好像也只有ie里能用。

5、将css从页面里剥离,放在单独的文件里,这样能够使用缓存、压缩等策略,当然要注意不要引入过多的css文件,会增加http请求的。

6、避免使用滤镜。IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素(不仅仅是图片)它都会运算一次,增加了内存开支,因此它的问题是多方面的。完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果确实需要使用AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。

javascript性能优化(不定期整理)

javascript的性能优化通常包括两个方面,一是代码体积减小带来的下载时间减少,二是代码效率提高带来的执行时间减少。

关于代码体积的改善

javascript不同于c、c++这样的编译语言,开发人员不需要考虑变量名长度及注释等,因为在编译时这些都会被删除或替换。javascript的所有内容都需要下载到客户端执行,这些无意义的东西最好还是删除或缩小为妙。下面常用的减少代码体积的方法:

1、删除注释。

2、删除空格,制表符,换行符。

3、替换变量名。

当然,上面的三种情况不需要手工去做的,我们可以使用一些压缩工具JSMinYUI Compressor,还有我正在用的PackerTB Compressor等。经研究表明,即使是通过Gzip压缩后的代码,如果通过上面那些工具先进行一步压缩,仍可减少5%以上的体积。

4、避免使用布尔值。在js里true等于1,false等于0。

5、缩短否定检测。js代码里有许多检测某个值是否有效的判断语句,像

if(typeof g == undefined){
 return;
}
if(g == null){
 return;
}
if(g == false){
 return;
}
if (g == 0){
  return;
}

上面的语句除非变量g可以为0,或没有在作用域链中出现过,我们要用0和undefined判断,否则,这样写更简洁:

if (!g){
  retrun;
}

关于代码效率的改善

=======================================(分割线,以上2009-07-08)

1、仔细检查函数中所有使用的变量,如果有一个变量不是当前作用域定义的,而且使用了不止一次,那么我们就应该把这个变量保存在局部变量中,而使用这个局部变量来进行读写操作。这样可以帮助我们将作用域外的变量的搜索深度减少到1。这对全局变量尤为重要,因为全局变量总是被放到作用域链的最后位置来搜索。

2、避免使用with语句。因为它会修改执行上下文(Execution Context)的作用域链,在最前面添加一个对象(Variable Object)。这就意味着在执行with的过程中,实际上的局部变量都被移到作用域链上的第二个位置,这会带来性能上的损失。

3、如果你确定一段代码肯定会抛出异常,那么就要避免使用try-catch,因为catch分支在作用域链上的处理方法和with是一样的。但try分支的代码是没有性能损失的,所以还是建议用try-catch来捕获那些不可预知的错误。

======================================(2009-06-19的分割线)

4、使用join代替“+”或“for”连接字符串。例如:

var wrap = [ vanillaDiv
 , '<div style="position:absolute;top:0px;left:0px;padding:0px;'
 , 'margin:0px;overflow:visible;height:'
 , Dock.height, 'px;width:', Dock.width
 , 'px;"></div></div>'
 ].join('');

现代浏览器对“+”连接字符串都做了相应的优化,可以根据应用情况和自己喜好权衡使用。这有文章Fastest way to build an HTML string,作者James Padolsey,一个很牛逼的18岁小孩。

5、将可反复利用的内容放在循环体外部。例如:

下面这个函数从DOM树中选择一个元素,然后对这个元素做一些事情。如果像下面这样,需要每次都从树中去找container这个元素,而且会每次都进行someArray的长度计算。

for(var i = 0; i < someArray.length; i++) {
   var container = document.getElementById('container');
   dosomething();
}

改进一下,写成下面这样,达到了同样的目的,却不用每次搜索DOM树了,也不用每次都计算someArray的长度了。

var container = document.getElementById('container');
for(var i = 0, len = someArray.length; i < len;  i++) {
   dosomething();
}

类似的应用还有地图蒙板这个例子,每次鼠标移动都要调用mbCtrl.move()这个函数,可以看一下index.js里的112-115行,如果直接这样用$(“#mapContainer > div:nth-child(3)”)选择器选择,每次鼠标移动都要搜索DOM树,实际应用时效率奇低呀。改进一下,

var mbCtrl = {
    init:function(){
        this.div3=$("#mapContainer > div:nth-child(3)");
    },
    move:function(){
        this.div3=css({top:'0',left:'0',width:this.mwth,height:tc,display:"block",background:"#f00"});
    }
}

在一开始就把要操作的对象选择出来,缓存起来,这样一个小改动,在一些浏览器(ie)里有成百倍的效率提高。

6、用{}代替new Object(),用[]代替new Array()。

这个不多说了,就是使用var obj={},arr=[]代替var obj=new Object(),arr=new Array(),这样就不用再进行一次实例化了,而且减少了代码体积。至于到底啥时候用object,啥时候用array,”A common error in JavaScript programs is to use an object when an array is required or an array when an object is required. The rule is simple: when the property names are small sequential integers, you should use an array. Otherwise, use an object.” – Douglas Crockford

=============================================(2009-07-03分割线)

7、if与switch的使用。if语句在js里应用很多,因为用户可能的操作习惯实在是没有规律,应该尽量减少判断执行次数。通常采用的优化方式有两种,最大可能排最前和分组判断。举个例子:

if (value > 3){
  if (value == 5){
    return result5;
  }
  else if (value == 4){
    return result4;
  }
  else{
    return result6;
  }
}
else{
  if (!value){
    return result0;
  }
  else{
    if (value == 1){
      return result1;
    }
    else if (value == 2){
      return result2;
    }
    else{
      return result3;
    }
  }
}

让面的例子对if判断进行了分组,而且把最可能出现的判断条件放在了前面。当判断条件较多时,使用switch语句的效率要好于if语句,可以根据情况尽量使用switch语句处理。js里还有个好处就是case语句里可以使用任何类型的值,例如:

switch(value){
case "yellow":
  alert('fuck');
  break;
case "green":
  alert('yada');
  break;
case 3:
  alert("what");
  break;
default:
  alert("go to hell");
}

这里还有个据说更好的方法:

switch(value){
case 0:
return result0;
case 1:
return result1;
case 2:
return result2;
case 3:
return result3;
case 4:
return result4;
case 5:
return result5;
}

var results = [result0, result1, result2, result3, result4, result5];
return results[value];

可以看出使用switch和数组达到了相同目的,但使用数组的效率更高一些。这里有个测试地址http://www.nczonline.net/experiments/javascript/performance/conditional-branching/

8、使用更有效率的循环写法。据说能节省50%的执行时间:

var values = [1,2,3,4,5];
var length = values.length;
//for loop
for (var i=length; i--;){
process(values[i]);
}
//do-while loop
var j=length;
do {
process(values[--j]);
} while (j);
//while loop
var k=length;
while (k--){
process(values[k]);
}

至于for-in循环,再对对象进行操作时很好用,但比较低效,所以除非要遍历对象,否则还是不要用它了。

9、优先使用javascript内置方法。js的内置方法都是在浏览器里的,通常都是由C++编译的,这比自己写的js方法要快很多很多。

10、最小化语句数量。对于js这种解释性语言,有理由相信语句越少,执行所需的时间越短。有几个例子:

var a = 3;
var b = "yada";
var c = [1,2,3];
var d = new Date();

var name = names[i];
i++;

var obj = new Object();
obj.color = "red";
obj.num = 5;

优化一下:

var a = 3, b = "yada", c = [1,2,3], d = new Date();

var name = names[i++];

var obj = {color:"red", num:5};