css动画transform与animation属性详情

css 动画:

transform:2D变换 //参照:https://developer.mozilla.org/en/CSS/transform

Syntax:
transform: <transform-function> [<transform-function>]* | none

Values:
transform-function;
none;

transform-function:
matrix:
transform: matrix(a, c, b, d, tx, ty) //指定一个由6个值组成的二维变换矩阵
a:宽度缩放比
b:以x轴进行倾斜
c:以y轴进行倾斜
d:高度缩放比
tx:x轴位移
ty:y轴位移

rotate:
transform: rotate(angle) //旋转效果 e.g. rotate(30deg)

scale:
transform: scale(sx[, sy]) //由指定[SX,SY]描述进行二维缩放操作
scaleX:
transform: scaleY(sy) //x轴缩放
scaleY:
transform: scaleY(sy) //y轴缩放

skew:
transform: skew(ax[, ay]) //以x轴或y轴进行倾斜
skewX:
transform: skewX(angle) //以x轴进行倾斜
skewY:
transform: skewY(angle) //以y轴进行倾斜

translate:
transform: translate(tx[, ty]) //以x轴或y轴进行位移
translateX:
transform: translateX(tx) //以x轴进行位移
translateY:
transform: translateY(ty) //以y轴进行位移

transform-origin:变换起点 //参照:https://developer.mozilla.org/en/CSS/transform-origin

Syntax:
transform-origin: [ <percentage> | <length> | left | center | right ]
[ <percentage> | <length> | top | center | bottom ] ?
transform-origin: [ left | center | right ] || [ top | center | bottom ]

Examples:
transform-origin: 100% 100%;
transform-origin: 100px 100px;
transform-origin: bottom right;
3D transform:3D变换

matrix3d:
transform: matrix3d(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4)

rotate3d: 3D旋转
transform: rotate3d(x, y, z, a)
x: <number> 表示旋转轴的x坐标向量
y: <number> 表示旋转轴的y坐标向量
z: <number> 表示旋转轴的z坐标向量
a: <angle> 旋转角度
rotateX:
rotateX(a) //X轴旋转度
rotateY:
rotateY(a) //Y轴旋转度
rotateZ:
rotateZ(a) //Z轴旋转度

scale3d: 3D缩放
transform:scale3d(sx, sy, sz)
scale3dX(s)
scale3dY(s)
scale3dZ(s)

translate3d: 3D位移
transform: translate3d(x, y, z)
translateX
translateY
translateZ

perspective: 视角
transform: perspective(lenght)

transform-style: preserve-3d || flat //开启3D视角

transform-origin-z: 变换起点的Z轴起点

More:
transform-function详细介绍: https://developer.mozilla.org/en/CSS/transform-function
Intro to CSS 3D transforms: http://desandro.github.com/3dtransforms/
transition:过渡

Syntax:
transition: [ <transition-property> || <transition-duration> || <transition-timing-function> || <transition-delay> ]

transition-property: none | all | [<property-name>][, <property-name>]* //指定将使用过渡效果的css属性,可指定多个

transition-duration: time[, time]*
//指定完成过渡的时间,可指定多个。指定多个时每个时间对于transition-property中的属性,time数量少于property数量则缺少的time值默认为0s,多出时后面的time将弃用

transition-timing-function: <timing-function> [, <timing-function>]* //建立一个加速度曲线来改变过渡的持续时间
Values:
linear //等价于 cubic-bezier(0,0,1,1)
ease //默认值,等价于 cubic-bezier(0.25,0.1,0.25,1)
ease-in //等价于 cubic-bezier(0.42,0,1,1)
ease-out //等价于cubic-bezier(0,0,0.58,1)
ease-in-out //等价于cubic-bezier(0.42,0,0.58,1)
cubic-bezier(n,n,n,n) //指定一个赛贝尔曲线
step-start //equivalent to steps(1, start)
step-end //equivalent to steps(1, end)
steps(start,end)

transition-delay:time[, time]* //延时执行过渡动画,可指定多个时间值,与transition-property对应
Animation:动画
Syntax:
animation: [ <animation-name> || <animation-duration> || <animation-timing-function> || <animation-delay> ||
<animation-iteration-count> || <animation-direction>]
[, [<animation-name> || <animation-duration> || <animation-timing-function> || <animation-delay> ||
<animation-iteration-count> || <animation-direction>] ]*
animation-name: none | <name> [, none | <name>]* //动画名
animation-duration: <time> [, <time>]* //持续时长
animation-timing-function: <timing-function> [, <timing-function>]* //建立一个加速度曲线来改变过渡的持续时间
animation-delay: <time> [, <time>]* //指定动画延时执行的时间
animation-iteration-count: infinite | <number> [, infinite | <number>]* //动画循环执行的次数
animation-direction: normal | alternate | reverse | alternate-reverse[, normal | alternate | reverse | alternate-reverse]* //动画执行的步骤顺序
animation-fill-mode: none | forwards | backwards | both [, none | forwards | backwards | both]* //动画填充模式
animation-play-state: running | paused [, running | paused]* //动画执行状态

@keyframes: //关键帧
Syntax:
@keyframes <identifier> {
[ [ from | to | <percentage> ] [, from | to | <percentage> ]* block ]*
}

@keyframes run {
0% { top: 0; left: 0; }
30% { top: 50px; }
68%, 72% { left: 50px; }
100% { top: 100px; left: 100%; }
}
创建Animation:
1、创建动画帧:keyframes
2、调用动画名:animation-name
3、设置动画持续时长:animation-duration
4、设置动画变换频率:animation-timing-function
5、设置动画开始时间:animation-delay
6、设置动画播放次数:animation-iteration-count

transparent background for IE6

<!--[if IE]>
   
   <style type="text/css">

   .color-block { 
       background:transparent;
       filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#50990000,endColorstr=#50990000); 
       zoom: 1;
    } 

    </style>

<![endif]-->

浅谈ECMAScript 5 严格模式(Strict Mode)

自ECMAScript 5开始,增加了一个严格模式(Strict Mode)的新特性。
ECMAScript 5虽然可以跟前一版的ECMAScript 3相容(ECMAScript 4已废弃) ,
但是,当我们宣告为”Strict Mode”后,那些ECMAScript 5不再建议使用的ECMAScript 3的旧语法会被全面禁止。一旦出现,便会出现错误或抛出异常(Exception)。

Strict Mode 的宣告方式有两种:
若要在全域范围内宣告使用Strict Mode,只需在程式码的第一行加上下面叙述,如:

"use strict"

也可以在指定的函数内宣告使用Strict Mode,在函数的第一行加上下面叙述,如:

// Non-strict code...
function  func_UseStrictMode() {
  "use strict" ;
  // ... your code ...
}

Continue reading

利用 mod_pagespeed 实现极速

简介
来自 Google 的 mod_pagespeed Apache 模块被设计为一种 “插入式” 模块,可供 Apache Web 托管商插入其服务器安装,并立即实现页面加载速度的显著提高。 如果您还不确定如何加速您的网站,或者尚未优化您的配置性能,那么此模块就应该是您寻找已久的解决方案。举例来说,对于使用开箱即用配置与安装的 WordPress 博主,此模块能带来很大的改变。
mod_pagespeed 模块在一个模块中结合了优化页面加载速度的最佳实践,并且可自动执行所有必要的步骤。

先决条件
要使用 mod_pagespeed,您需要安装可在 Linux 上运行的 Apache 2.2 版本,32 位或 64 位均可,同时安装 mod_deflate 模块。
目前,mod_pagespeed 不支持 Windows 或旧版本的 Apache(根据他们的文档和常见问题解答来看,我认为近期他们不会为这些版本提供支持)。

速度的定义

无论您的 Internet 连接速度如何,您总是希望能够更快地加载您的网页。将页面内容发送给您的 Web 服务器也希望它的速度更快,原因有二:如果企业的服务器速度缓慢,就会导致客户丢失。此外,如果企业为您提供了更快的个别页面加载速度,那么就能将其自己的服务器用于为其他人提供更多页面。您可能每天访问他们的页面一次,但他们每天要为其他客户提供 100,000 次相同的页面。对于这些企业来说,即便是细微的速度提升也有着重大的意义。

就本文的目的而言,我们将从用户的视角定义 “速度”:页面加载时间。能够迅速加载的网页将被视为快速,如 www.google.com,其页面加载时间非常短。相反,如果某个假象站点仅有一台服务器,运行在陈旧的 Pentium II 600 MHz 之上,而且包含 40 个庞大的镜像文件,那么这个站点无疑会非常慢,其页面加载时间非常长。此外,如果一个网页在每天仅有少数人访问时速度较快,在数千名用户都在 10 分钟的时间内访问该网站时,该网站仍然有可能变得极为缓慢。因此,“速度” 定义为使您从 A 点到 B 点所用的时间,其中 A 点 = 您在地址栏中键入某些内容之后按下 “回车键” 的时候,而 B 点 = 页面完全载入浏览器的时间。

从 Web 服务器的角度来看,提高速度(而无需更改硬件)的最佳方法就是更快地发送更少量的数据。更具体地来说,您希望降低机器的延迟(延迟 = 响应时间),并减小传输的数据大小(所传输的数据的物理 Kb 数)。因此,为了 “加速” 一个网站,无论是从 Web 服务的视角,还是从用户的视角来说,您都需要减少服务器的延迟,同时减小所传输的数据大小。

如何提高速度

提高网站速度的全部可行战术可分为五大类:最大化缓存、最小化查找、最小化每条请求的开销、最小化数据大小,以及优化浏览器的呈现。请注意,各分类描述极限行为的方式,例如 “最大化” 或 “最小化”,举例来说,不存在 “打开” 或者 “关闭” 一种特性或者设置的简单解决方案。下面我们来详解各分类,并说明其工作方式。

Continue reading

如何选择开源许可证?

如何为代码选择开源许可证,这是一个问题。
世界上的开源许可证,大概有上百种。很少有人搞得清楚它们的区别。即使在最流行的六种—-GPL、BSD、MIT、Mozilla、Apache和LGPL—-之中做选择,也很复杂。
乌克兰程序员Paul Bagwell,画了一张分析图,说明应该怎么选择。这是我见过的最简单的讲解,只用两分钟,你就能搞清楚这六种许可证之间的最大区别。
下面是中文版,请点击看大图。

 

原文网址:http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html

提高web应用性能之JavaScript性能调优

JavaScript 性能调优

JavaScript 语言由于它的单线程和解释执行的两个特点,决定了它本身有很多地方有性能问题,所以可改进的地方有不少。

eval 的问题:

比较下述代码:
清单 1. eval 的问题

				 
 var reference = {}, props = “p1”; 
 eval(“reference.” + props + “=5”) 

 var reference = {}, props = “p1”; 
 reference[props] = 5

有“eval”的代码比没有“eval”的代码要慢上 100 倍以上。

主要原因是:JavaScript 代码在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用 var 申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是 undefined,并将那些以 function 定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。但是,如果你使用了“eval”,则“eval”中的代码(实际上为字符串)无法预先识 别其上下文,无法被提前解析和优化,即无法进行预编译的操作。所以,其性能也会大幅度降低。

Function 的用法:

比较下述代码:
清单 2. function 的用法

				 
 var func1 = new Function(“return arguments[0] + arguments[1]”);
 func1(10, 20); 

 var func2 = function(){ return arguments[0] + arguments[1] };
 func2(10, 20);

这里类似之前提到的“eval”方法,这里“func1”的效率会比“func2”的效率差很多,所以推荐使用第二种方式。

函数的作用域链(scope chain):

JavaScript 代码解释执行,在进入函数内部时,它会预先分析当前的变量,并将这些变量归入不同的层级(level),一般情况下:

局部变量放入层级 1(浅),全局变量放入层级 2(深)。如果进入“with”或“try – catch”代码块,则会增加新的层级,即将“with”或“catch”里的变量放入最浅层(层 1),并将之前的层级依次加深。

参考如下代码:
清单 3. 函数作用域链

				 
 var myObj = … .. 
… .. 
 function process(){ 
 var images = document.getElementsByTagName("img"), 
 widget = document.getElementsByTagName("input"), 
 combination = []; 
 for(var i = 0; i < images.length; i++){ 
 combination.push(combine(images[i], widget[2*i])); 
 } 
 myObj.container.property1 = combination[0]; 
 myObj.container.property2 = combination[combination.length-1]; 
 }

这里我们可以看到,“images”,“widget”,“combination”属于局部变量,在层 1。“document”,“myObj”属于全局变量,在层 2。

变量所在的层越浅,访问(读取或修改)速度越快,层越深,访问速度越慢。所以这里对“images”,“widget”,“combination”的访问速度比“document”,“myObj”要快一些。所以推荐尽量使用局部变量,可见如下代码:
清单 4. 使用局部变量

				 
 var myObj = … .. 
… .. 
 function process(){ 
 var doc = document;
 var images = doc.getElementsByTagName("img"), 
 widget = doc.getElementsByTagName("input"), 
 combination = []; 
 for(var i = 0; i < images.length; i++){ 
 combination.push(combine(images[i], widget[2*i])); 
 } 
 myObj.container.property1 = combination[0]; 
 myObj.container.property2 = combination[combination.length-1]; 
 }

我们用局部变量“doc”取代全局变量“document”,这样可以改进性能,尤其是对于大量使用全局变量的函数里面。

再看如下代码:
清单 5. 慎用 with

				 
 var myObj = … .. 
… .. 
 function process(){ 
 var doc = document; 
    var images = doc.getElementsByTagName("img"), 
 widget = doc.getElementsByTagName("input"), 
 combination = []; 
 for(var i = 0; i < images.length; i++){ 
 combination.push(combine(images[i], widget[2*i])); 
 } 
 with (myObj.container) {
 property1 = combination[0];
 property2 = combination[combination.length-1];
				 }
 }

加上“with”关键字,我们让代码更加简洁清晰了,但是这样做性能会受影响。正如之前说的,当我们进入“with”代码块时,“combination”便从原来的层 1 变到了层 2,这样,效率会大打折扣。所以比较一下,还是使用原来的代码:
清单 6. 改进 with

				 
 var myObj = … .. 
… .. 
 function process(){ 
 var doc = document; 
 var images = doc.getElementsByTagName("img"), 
 widget = doc.getElementsByTagName("input"), 
 combination = []; 
 for(var i = 0; i < images.length; i++){ 
 combination.push(combine(images[i], widget[2*i])); 
 } 
 myObj.container.property1 = combination[0];
 myObj.container.property2 = combination[combination.length-1];
      }

但是这样并不是最好的方式,JavaScript 有个特点,对于 object 对象来说,其属性访问层级越深,效率越低,比如这里的“myObj”已经访问到了第 3 层,我们可以这样改进一下:
清单 7. 缩小对象访问层级

				 
 var myObj = … .. 
… .. 
 function process(){ 
 var doc = document; 
    var images = doc.getElementsByTagName("img"), 
 widget = doc.getElementsByTagName("input"), 
 combination = []; 
 for(var i = 0; i < images.length; i++){ 
 combination.push(combine(images[i], widget[2*i])); 
 } 
 var ctn = myObj.container;
 ctn.property1 = combination[0];
 ctn.property2 = combination[combination.length-1];
      }

我们用局部变量来代替“myObj”的第 2 层的“container”对象。如果有大量的这种对对象深层属性的访问,可以参照以上方式提高性能。

字符串(String)相关

字符串拼接

经常看到这样的代码:
清单 8. 字符串简单拼接

				 
 str += “str1” + “str2”

这是我们拼接字符串常用的方式,但是这种方式会有一些临时变量的创建和销毁,影响性能,所以推荐使用如下方式拼接:
清单 9. 字符串数组方式拼接

				 
 var str_array = []; 
 str_array.push(“str1”); 
 str_array.push(“str2”); 
 str = str_array.join(“”);

这里我们利用数组(array)的“join”方法实现字符串的拼接,尤其是程序的老版本的 Internet Explore(IE6)上运行时,会有非常明显的性能上的改进。

当然,最新的浏览器(如火狐 Firefox3+,IE8+ 等等)对字符串的拼接做了优化,我们也可以这样写:
清单 10. 字符串快速拼接

				 
 str +=“str1”
 str +=“str2”

新的浏览器对“+=”做了优化,性能略快于数组的“join”方法。在不久的将来更新版本浏览器可能对“+”也会做优化,所以那时我们可以直接写:str += “str1” + “str2”。

隐式类型转换

参考如下代码:
清单 11. 隐式类型转换

				 
 var str = “12345678”, arr = []; 
 for(var i = 0; i <= s.length; i++){ 
 arr.push( str.charAt(i)); 
 }

这里我们在每个循环时都会调用字符串的“charAt”方法,但是由于我们是将常量“12345678”赋值给“str”,所以“str” 这里事实上并不是一个字符串对象,当它每次调用“charAt”函数时,都会临时构造值为“12345678”的字符串对象,然后调用“charAt”方 法,最后再释放这个字符串临时对象。我们可以做一些改进:
清单 12. 避免隐式类型转换

				 
 var str = new Stirng(“12345678”), arr = []; 
 for(var i = 0; i <= s.length; i++){ 
 arr.push( str.charAt(i)); 
 }

这样一来,变量“str”作为一个字符串对象,就不会有这种隐式类型转换的过程了,这样一来,效率会显著提高。

字符串匹配

JavaScript 有 RegExp 对象,支持对字符串的正则表达式匹配。是一个很好的工具,但是它的性能并不是非常理想。相反,字符串对象(String)本身的一些基本方法的效率是非常 高的,比如“substring”,“indexOf”,“charAt”等等,在我们需要用正则表达式匹配字符串时,可以考虑一下:

  1. 是否能够通过字符串对象本身支持的基本方法解决问题。
  2. 是否可以通过“substring”来缩小需要用正则表达式的范围。

这些方式都能够有效的提高程序的效率。

关于正则表达式对象,还有一点需要注意,参考如下代码:
清单 13. 正则表达式

				 
 for(var i = 0; i <= str_array.length; i++){ 
 if(str_array[i].match(/^s*extras/)){ 
……………………
 } 
 }

这里,我们往“match”方法传入“/^s*extras/”是会影响效率的,它会构建临时值为“/^s*extras/”的正则表达式对象,执行“match”方法,然后销毁临时的正则表达式对象。我们可以这样做:
清单 14. 利用变量

				 
 var sExpr = /^s*extras/;
 for(var i = 0; i <= str_array.length; i++){ 
 if(str_array[i].match(sExpr)){ 
……………………
 } 
 }

这样就不会有临时对象了。

setTimeout 和 setInterval

“setTimeout”和“setInterval”这两个函数可以接受字符串变量,但是会带来和之前谈到的“eval”类似的性能问题,所以建议还是直接传入函数对象本身。

利用提前退出

参考如下两段代码:
清单 15. 利用提前退出

				 
  // 代码 1
 var name = … .; 
 var source = …… ; 
 if(source.match(/ …… /)){ 
……………………………
 } 

 // 代码 2
 var name = … .; 
 var source = …… ; 
 if(name.indexOf( … ) &&source.match(/ …… /)){ 
……………………………
 }

代码 2 多了一个对“name.indexOf( … )”的判断,这使得程序每次走到这一段时会先执行“indexOf”的判断,再执行后面的“match”,在“indexOf”比“match”效率高很 多的前提下,这样做会减少“match”的执行次数,从而一定程度的提高效率。

DOM 操作性能调优

JavaScript 的开发离不开 DOM 的操作,所以对 DOM 操作的性能调优在 Web 开发中也是非常重要的。

Repaint 和 Reflow

Repaint 也叫 Redraw,它指的是一种不会影响当前 DOM 的结构和布局的一种重绘动作。如下动作会产生 Repaint 动作:

  1. 不可见到可见(visibility 样式属性)
  2. 颜色或图片变化(background, border-color, color 样式属性)
  3. 不改变页面元素大小,形状和位置,但改变其外观的变化

Reflow 比起 Repaint 来讲就是一种更加显著的变化了。它主要发生在 DOM 树被操作的时候,任何改变 DOM 的结构和布局都会产生 Reflow。但一个元素的 Reflow 操作发生时,它的所有父元素和子元素都会放生 Reflow,最后 Reflow 必然会导致 Repaint 的产生。举例说明,如下动作会产生 Repaint 动作:

  1. 浏览器窗口的变化
  2. DOM 节点的添加删除操作
  3. 一些改变页面元素大小,形状和位置的操作的触发

减少 Reflow

通过 Reflow 和 Repaint 的介绍可知,每次 Reflow 比其 Repaint 会带来更多的资源消耗,我们应该尽量减少 Reflow 的发生,或者将其转化为只会触发 Repaint 操作的代码。

参考如下代码:
清单 16. reflow 介绍

				 
 var pDiv = document.createElement(“div”); 
 document.body.appendChild(pDiv);----- reflow
 var cDiv1 = document.createElement(“div”); 
 var cDiv2 = document.createElement(“div”); 
 pDiv.appendChild(cDiv1);----- reflow
 pDiv.appendChild(cDiv2);----- reflow

这是我们经常接触的代码了,但是这段代码会产生 3 次 reflow。再看如下代码:
清单 17. 减少 reflow

				 
 var pDiv = document.createElement(“div”); 
 var cDiv1 = document.createElement(“div”); 
 var cDiv2 = document.createElement(“div”); 
 pDiv.appendChild(cDiv1); 
 pDiv.appendChild(cDiv2); 
 document.body.appendChild(pDiv);----- reflow

这里便只有一次 reflow,所以我们推荐这种 DOM 节点操作的方式。

关于上述较少 Reflow 操作的解决方案,还有一种可以参考的模式:
清单 18. 利用 display 减少 reflow

				 
 var pDiv = document.getElementById(“parent”); 
 pDiv.style.display = “none”----- reflow

 pDiv.appendChild(cDiv1); 
 pDiv.appendChild(cDiv2); 
 pDiv.appendChild(cDiv3); 
 pDiv.appendChild(cDiv4); 
 pDiv.appendChild(cDiv5); 
 pDiv.style.width = “100px”; 
 pDiv.style.height = “100px”; 

 pDiv.style.display = “block”----- reflow

先隐藏 pDiv,再显示,这样,隐藏和显示之间的操作便不会产生任何的 Reflow,提高了效率。

特殊测量属性和方法

DOM 元素里面有一些特殊的测量属性的访问和方法的调用,也会触发 Reflow,比较典型的就是“offsetWidth”属性和“getComputedStyle”方法。
图 1. 特殊测量属性和方法
图 1. 特殊测量属性和方法

这些测量属性和方法大致有这些:

  • offsetLeft
  • offsetTop
  • offsetHeight
  • offsetWidth
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • getComputedStyle()
  • currentStyle(in IE))

这些属性和方法的访问和调用,都会触发 Reflow 的产生,我们应该尽量减少对这些属性和方法的访问和调用,参考如下代码:
清单 19. 特殊测量属性

				 
 var pe = document.getElementById(“pos_element”); 
 var result = document.getElementById(“result_element”); 
 var pOffsetWidth = pe.offsetWidth;
 result.children[0].style.width  = pOffsetWidth; 
 result.children[1].style.width  = pOffsetWidth; 
 result.children[2].style.width  = pOffsetWidth; 
…………其他修改…………

这里我们可以用临时变量将“offsetWidth”的值缓存起来,这样就不用每次访问“offsetWidth”属性。这种方式在循环里面非常适用,可以极大地提高性能。

样式相关

我们肯定经常见到如下的代码:
清单 20. 样式相关

				 
 var sElement = document.getElementById(“pos_element”); 
 sElement.style.border = ‘ 1px solid red ’
 sElement.style.backgroundColor = ‘ silver ’
 sElement.style.padding = ‘ 2px 3px ’
 sElement.style.marginLeft = ‘ 5px ’

但是可以看到,这里的每一个样式的改变,都会产生 Reflow。需要减少这种情况的发生,我们可以这样做:

解决方案 1:
清单 21. className 解决方案

				 
 .class1 { 
 border: ‘ 1px solid red ’
 background-color: ‘ silver ’
 padding: ‘ 2px 3px ’
 margin-left: ‘ 5px ’
 } 
 document.getElementById(“pos_element”).className = ‘class1’ ;

用 class 替代 style,可以将原有的所有 Reflow 或 Repaint 的次数都缩减到一个。

解决方案 2:
清单 22. cssText 解决方案

				 
 var sElement = document.getElementById(“pos_element”); 
 var newStyle = ‘ border: 1px solid red; ’ + ‘ background-color: silver; ’ + 
                                 ‘ padding: 2px 3px; ’ + “margin-left: 5px;”
 sElement.style.cssText += newStyle;

一次性设置所有样式,也是减少 Reflow 提高性能的方法。

XPath

一个页面上往往包含 1000 多页面元素,在定位具体元素的时候,往往需要一定的时间。如果用 id 或 name 定位可能效率不会太慢,如果用元素的一些其他属性(比如 className 等等)定位,可能效率有不理想了。有的可能只能通过遍历所有元素(getElementsByTagName)然后过滤才能找到相应元素,这就更加低效 了,这里我们推荐使用 XPath 查找元素,这是很多浏览器本身支持的功能。
清单 23. XPath 解决方案

				 
 if(document.evaluate){ 
 var tblHeaders = document.evaluate(“//body/div/table//th”);
 var result = tblHeaders.iterateNext(); 
 while(result) { 
 result.style.border = “1px dotted blue”; 
 result ………………
 result = xpathResult.iterateNext(); 
 } 
 } else{ //getElementsByTagName() ……
 // 处理浏览器不支持 XPath 的情况
………………………………
 }

浏览器 XPath 的搜索引擎会优化搜索效率,大大缩短结果返回时间。

HTMLCollection 对象

这是一类特殊的对象,它们有点像数组,但不完全是数组。下述方法的返回值一般都是 HTMLCollection 对象:

  • document.images, document.forms
  • getElementsByTagName()
  • getElementsByClassName()

这些 HTMLCollection 对象并不是一个固定的值,而是一个动态的结果。它们是一些比较特殊的查询的返回值,在如下情况下,它们会重新执行之前的查询而得到新的返回值(查询结果),虽然多数情况下会和前一次或几次的返回值都一样:

  • Length 属性
  • 具体的某个成员

所以,HTMLCollection 对象对这些属性和成员的访问,比起数组来要慢很多。当然也有例外,Opera 和 Safari 对这种情况就处理的很好,不会有太大性能问题。

参考如下代码:
清单 24. HTMLConnection 对象

				 
 var items = [“test1”, “test2”, “test3”, ……………… ];
 for(var i = 0; i < items.length; i++){ 
………………………………
 } 

 var items = document.getElementsByTagName(“div”);
 for(var i = 0; i < items.length; i++){ 
…………………………………… . 
 }

上述两端代码,下面的效率比起上面一段要慢很多,因为每一个循环都会有“items.length”的触发,也就会导致“document.getElementsByTagName(..)”方法的再次调用,这便是效率便会大幅度下降的原因。我们可以这样解决:
清单 25. HTMLConnection 对象解决方案

				 
 var items = document.getElementsByTagName(“div”); 
 var len = items.length
 for(var i = 0; i < len; i++){ 
…………………………………… . 
 }

这样一来,效率基本与普通数组一样。

动态创建 script 标签

加载并执行一段 JavaScript 脚本是需要一定时间的,在我们的程序中,有时候有些 JavaScript 脚本被加载后基本没有被使用过 (比如:脚本里的函数从来没有被调用等等)。加载这些脚本只会占用 CPU 时间和增加内存消耗,降低 Web 应用的性能。所以推荐动态的加载 JavaScript 脚本文件,尤其是那些内容较多,消耗资源较大的脚本文件。
清单 26. 创建 script 标签

 if(needXHR){ 
 document.write(“<script type= ’ test/JavaScript ’ src= 'dojo_xhr.js' >”); 
 } 
 if(dojo.isIE){ 
 document.write(“<script type= ’ test/JavaScript ’ src= 'vml.js' >”); 
 }

XMLHttpRequest对象详解

一直用习惯了Jquery的$.Ajax,之前面试时有一笔试题要求用原生Javascript写一个AJax请求,特做一个整理。

什么是Ajax?

Ajax代表异步JavaScript和XML。简言之,它是使用XMLHttpRequest对象与服务器端脚本进行通信。它可以发送以及接收各种格式的信息,包括JSON,XML,HTML和甚至文本文件。然而,AJAX的最有吸引力的的特征是它的“异步”的性质,这意味着它可以做这一切,而无需刷新页面。这使您可以更新部分基于用户事件页面。
AJax的两个特点是,你可以:

  • 无需重新加载页面对服务器的请求
  • 接收和处理来自服务器的数据

如何创建一个XMLHttpRequest对象?

最简单的方法是:

//创建xhr对象
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
    httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}

//事件响应
httpRequest.onreadystatechange = nameOfTheFunction;
<pre>httpRequest.onreadystatechange = function(){
    // process the server response
};
<pre>//发送请求
httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send(null);

XMLHttpRequest对象的属性与方法:

XHR 请求:

open(method,url,async):

指定请求的类型,URL,如果请求应当异步处理或没有。

method: 设定请求类型,GET或POST
url: 请求地址
async: true (异步) or false (同步)

send(string):

向服务器发送请求。

string: 只在使用POST方式请求的时候使用

setRequestHeader(header,value):

添加请求主机头信息。

header:指定的头名
value:指定的标头值

XHR 响应:
responseText:作为一个字符串的响应数据

responseXML:作为XML的响应数据


XHR readyState:

onreadystatechange: readyState值改变时的触发事件

readyState:

存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

  • 0: 请求未初始化
  • 1: 服务器连接已建立
  • 2: 请求已接收
  • 3: 请求处理中
  • 4: 请求已完成,且响应已就绪

status:

HTTP响应状态码

  • 200: “OK”
  • 404: 未找到页面

在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务。

当 readyState 等于 4 且状态为 200 时,表示响应已就绪:

xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
 }

<strong>
一个简单的完整示例:</strong>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
  Make a request
</span>
<script type="text/javascript">
(function() {
  var httpRequest;
  document.getElementById("ajaxButton").onclick = function() { makeRequest('test.html'); };

  function makeRequest(url) {
    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
      httpRequest = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
      try {
        httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
      }
      catch (e) {
        try {
          httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (e) {}
      }
    }

    if (!httpRequest) {
      alert('Giving up :( Cannot create an XMLHTTP instance');
      return false;
    }
    httpRequest.onreadystatechange = alertContents;
    httpRequest.open('GET', url);
    httpRequest.send();
  }

  function alertContents() {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        alert(httpRequest.responseText);
    } else {
      alert('There was a problem with the request.');
    }
  }
}
} //missing closing bracket added by bwalton 5/11/11.
)();
</script>

YSlow使用指南[中文版]

YSlow分析网页,并提出如何提高其性能的基础上一套规则,高性能的网页。我搜索一下”Yslow使用说明“,发现都是旧版本Yslow的使用介绍。于是翻译了一下yahoo官方关于新版Yslow的的使用帮助,希望给初次使用Yslow的朋友一些帮助。

注:英文不是很好,对着翻译软件翻译的,有不对的地方,大家指正。

安装 YSlow

先安装 Firebug  https://addons.mozilla.org/en-US/firefox/addon/1843

Firebug 帮助文档 http://www.getfirebug.com/docs.html.

再下载安装  http://developer.yahoo.com/yslow

使用Yslow

Yslow是运行在Firebug窗口下,所有要运行Yslow,必须安装Firebug。

有两种方法启动Yslow

1、打开Firebug窗口,选择Yslow选项。

2、直接点击浏览器右下角的Yslow启动按钮。

你第一次打开Yslow时,以下图像作为Firebug的一部分被显示在的浏览器窗口。

点击 Run Test 运行Yslow,也可以点击 Grade, Components, 或Statistics选项开始对页面的分析。

你可以选择 Autorun YSlow each time a web page is loaded 它将自动对以后打开页面进行分析,您也可以右击YSlow状态栏,然后选择或取消自动运行。

Yslow视图

YSlow显示测试结果的分析,分为等级、组件、统计信息。你可以浏览这些观点之间选择标签以观的名字在YSlow标签的Firebug控制台。

以下是说明的等级、组件、统计信息。

一、等级视图

  查看一个分析,选择页面的性能等级标签或点击网页的字母等级在状态栏这页纸的底部。

视图显示了等级为网页的成绩单。整个字母等级为页面显示在顶部随着全面数值的表现。这个页面是基于22可分级的高性能网页的规则(见性能规则)。这些规则是列在按重要性的顺序,从最重要不重要。从 A 级到 F 级,A 级为最高。

下面是一个等级的例子:

如果页面与某一个规则无关,则显示 N/A ,表示不适用。

点击每一规则,都给出了改进建议。要查看更全面的改进方法进入前端性能优化指南

二、组件视图

分组显示页面组件,表格列出组件的信息,点击 Expand All展开显示给个分组内各的组件信息。

下面简要列在组件检视表:

TYPE:该组件的类型。该网页是由组成部分的下列类型: doc, js, css, flash, cssimage, image, redirect, favicon, xhr, and iframe.

SIZE(KB):该组件的大小以千字节。

GZIP(KB):该组件的gzip压缩的大小以千字节。

COOKIE RECEIVED(bytes):字节数在HTTP设置的Cookie响应头。

COOKIE SENT(bytes):节数的Cookie在HTTP请求报头

HEADERS:HTTP信息头,点击放大镜查看全面信息。

URL:链接地址

EXPIRES(Y/M/D):日期的Expires头,属于缓存设置一种。

RESPONSE TIME (ms):响应时间

ETAG:ETag响应头,也是缓存设置的一种

ACTION:额外的性能分析

三、统计信息视图

左侧图表显示是页面元素在空缓存的加载情况,右侧为页面元素使用缓存后的页面加载情况。我们可以看到,页面元素缓存后的使页面的http请求和页面总大小都减少,从而加快了页面打开时间。参看(页面的缓存设置

YSlow菜单栏

一、规则集

1 、YSlow ( 2版) -这一规则集包含了所有22个测试的规则。
2 、精英( V1导联) -这个规则集包含原始13规则中使用了YSlow 1.0 。
3、小网站或博客-这个规则集包含14个规则,适用于小型网站或博客。参照下方的图片,看看哪一种规则,在这个规则集。

请注意,最后选定的规则集成为默认的规则集。默认规则集可以是一个预定义的三个之一或您自己创建的一个。

要创建您自己的规则集,单击Rulesets下拉菜单旁边的 Edit 按钮。新的规则集屏幕将显示:

1、点击左侧 New Set 按钮,出现全部22调规则,勾选你所需的

2、点击 Save ruleset as… 保存,会弹出个命名窗口,命名就可以了。

3、你还可以对自定义的规则再次编辑或者删除。

YSlow 工具

YSlow的工具菜单上提供了多种报告工具,您可以使用获得的信息,以帮助您的网页分析。以下是截图工具菜单:

1、JSLint

JSLint收集所有外部和内部的JavaScript从目前的网页,提交给JSLint ,一个JavaScript验证,并打开一个单独的窗口了一份报告,存在问题,该网页的JavaScript的。该报告包括大致位置的源代码的问题。很多 时候,这些问题是语法错误,但JSLint寻找风格公约的问题和结构性问题。

2、All JS

收集所有外部和内部的JavaScript的网页,并显示在一个单独的脚本窗口。您可能想要使用这个工具来查看某个脚本,以及是否实际使用是正确的。

3、All JS Beautified

将js以人们可读的方式展示。

4、All JS Minified

收集所有外部和内嵌JavaScript,删除评论和白色空间以缩小的脚本。以改善网页的性能。

5、All CSS

收集所有的行内和外部的样式表在网页上,并将其显示在一个单独的窗口。

6、All Smush.it

如果您按一下所有Smush.it , Smush.it将运行在网页上所有的图片组成。此工具将告诉你该图像可被优化,并创建一个压缩文件,来优化图像。当您选择此工具你会看到输出如下所示:

以上就是Yslow的使用指南,结束。

转载声明:

原载:web前端优化

本文链接:YSlow使用指南

jQuery的deferred对象详解

jQuery的开发速度很快,几乎每半年一个大版本,每两个月一个小版本。

每个版本都会引入一些新功能。今天我想介绍的,就是从jQuery 1.5.0版本开始引入的一个新功能—-deferred对象

这个功能很重要,未来将成为jQuery的核心方法,它彻底改变了如何在jQuery中使用ajax。为了实现它,jQuery的全部ajax代码都被改写了。

但是,它比较抽象,初学者很难掌握,网上的教程也不多。所以,我把自己的学习笔记整理出来了,希望对大家有用。

本文不是初级教程,针对的读者是那些已经具备jQuery使用经验的开发者。如果你想了解jQuery的基本用法,请阅读我编写的《jQuery设计思想》《jQuery最佳实践》

======================================

jQuery的deferred对象详解

作者:阮一峰

一、什么是deferred对象?

开发网站的过程中,我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们都不是立即能得到结果的。

通常的解决方法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。

但是,在回调函数方面,jQuery的功能非常弱。为了改变这一点,jQuery开发团队就设计了deferred对象

简单说,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是”延迟”,所以deferred对象的含义就是”延迟”到未来某个点再执行。

它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口。它的主要功能,可以归结为四点。下面我们通过示例代码,一步步来学习。

二、ajax操作的链式写法

jQuery的ajax操作,传统写法是这样的:

  $.ajax({

    url: “test.html”,

    success: function(){
      alert(“哈哈,成功了!”);
    },

    error:function(){
      alert(“出错啦!”);
    }

  });

(运行代码示例1

在上面的代码中,$.ajax()接受一个对象参数,这个对象包含两个方法:success方法指定操作成功后的回调函数,error方法指定操作失败后的回调函数。

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是deferred对象,可以进行链式操作。

现在,新的写法是这样的:

  $.ajax(“test.html”)

  .done(function(){ alert(“哈哈,成功了!”); })

  .fail(function(){ alert(“出错啦!”); });

(运行代码示例2

可以看到,done()相当于success方法,fail()相当于error方法。采用链式写法以后,代码的可读性大大提高。

三、指定同一操作的多个回调函数

deferred对象的一大好处,就是它允许你自由添加多个回调函数。

还是以上面的代码为例,如果ajax操作成功后,除了原来的回调函数,我还想再运行一个回调函数,怎么办?

很简单,直接把它加在后面就行了。

  $.ajax(“test.html”)

  .done(function(){ alert(“哈哈,成功了!”);} )

  .fail(function(){ alert(“出错啦!”); } )

  .done(function(){ alert(“第二个回调函数!”);} );

(运行代码示例3

回调函数可以添加任意多个,它们按照添加顺序执行。

四、为多个操作指定回调函数

deferred对象的另一大好处,就是它允许你为多个事件指定一个回调函数,这是传统写法做不到的。

请看下面的代码,它用到了一个新的方法$.when()

  $.when($.ajax(“test1.html”), $.ajax(“test2.html”))

  .done(function(){ alert(“哈哈,成功了!”); })

  .fail(function(){ alert(“出错啦!”); });

(运行代码示例4

这段代码的意思是,先执行两个操作$.ajax(“test1.html”)和$.ajax(“test2.html”),如果成功了,就运行done()指定的回调函数;如果有一个失败或都失败了,就执行fail()指定的回调函数。

五、普通操作的回调函数接口(上)

deferred对象的最大优点,就是它把这一套回调函数接口,从ajax操作扩展到了所有操作。也就是说,任何一个操作—-不管是ajax操作还是本地操作,也不管是异步操作还是同步操作—-都可以使用deferred对象的各种方法,指定回调函数。

我们来看一个具体的例子。假定有一个很耗时的操作wait:

  var wait = function(){

    var tasks = function(){

      alert(“执行完毕!”);

    };

    setTimeout(tasks,5000);

  };

我们为它指定回调函数,应该怎么做呢?

很自然的,你会想到,可以使用$.when():

  $.when(wait())

  .done(function(){ alert(“哈哈,成功了!”); })

  .fail(function(){ alert(“出错啦!”); });

但是,有一个问题。$.when()的参数只能是deferred对象,所以必须对wait进行改写:

  var dtd = $.Deferred(); // 新建一个deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert(“执行完毕!”);

      dtd.resolve(); // 改变deferred对象的执行状态

    };

    setTimeout(tasks,5000);

    return dtd.promise();

  };

这里有两个地方需要注意。

首先,最后一行不能直接返回dtd,必须返回dtd.promise()。 原因是jQuery规定,任意一个deferred对象有三种执行状态—-未完成,已完成和已失败。如果直接返回dtd,$.when()的默认执行 状态为”已完成”,立即触发后面的done()方法,这就失去回调函数的作用了。dtd.promise()的目的,就是保证目前的执行状态—-也就 是”未完成”—-不变,从而确保只有操作完成后,才会触发回调函数。

其次,当操作完成后,必须手动改变Deferred对象的执行状态,否则回调函数无法触发。dtd.resolve()的作用,就是将dtd的执行状态从”未完成”变成”已完成”,从而触发done()方法。

最后别忘了,修改完wait之后,调用的时候就必须直接传入dtd参数。

  $.when(wait(dtd))

  .done(function(){ alert(“哈哈,成功了!”); })

  .fail(function(){ alert(“出错啦!”); });

(运行代码示例5

六、普通操作的回调函数接口(中)

除了使用$.when()为普通操作添加回调函数,还可以使用deferred对象的建构函数$.Deferred()。

这时,wait函数还是保持不变,我们直接把它传入$.Deferred():

  $.Deferred(wait)

  .done(function(){ alert(“哈哈,成功了!”); })

  .fail(function(){ alert(“出错啦!”); });

(运行代码示例6

jQuery规定,$.Deferred()可以接受一个函数作为参数,该函数将在$.Deferred()返回结果之前执行。并且,$.Deferred()所生成的Deferred对象将作为这个函数的默认参数。

七、普通操作的回调函数接口(下)

除了上面两种方法以外,我们还可以直接在wait对象上部署deferred接口。

  var dtd = $.Deferred(); // 生成Deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert(“执行完毕!”);

      dtd.resolve(); // 改变Deferred对象的执行状态

    };

    setTimeout(tasks,5000);

  };

  dtd.promise(wait);

  wait.done(function(){ alert(“哈哈,成功了!”); })

  .fail(function(){ alert(“出错啦!”); });

  wait(dtd);

(运行代码示例7

这里的关键是dtd.promise(wait)这一行,它的作用就是在wait对象上部署Deferred接口。正是因为有了这一行,后面才能直接在wait上面调用done()和fail()。

八、小结:deferred对象的方法

前面已经讲到了deferred对象的多种方法,下面做一个总结:

  (1) $.Deferred() 生成一个deferred对象。

  (2) deferred.done() 指定操作成功时的回调函数

  (3) deferred.fail() 指定操作失败时的回调函数

  (4) deferred.promise() 没有参数时,作用为保持deferred对象的运行状态不变;接受参数时,作用为在参数对象上部署deferred接口。

  (5) deferred.resolve() 手动改变deferred对象的运行状态为”已完成”,从而立即触发done()方法。

  (6) $.when() 为多个操作指定回调函数。

除了这些方法以外,deferred对象还有三个重要方法,上面的教程中没有涉及到。

  (7)deferred.then()

有时为了省事,可以把done()和fail()合在一起写,这就是then()方法。

  $.when($.ajax( “/main.php” ))

  .then(successFunc, failureFunc );

如果then()有两个参数,那么第一个参数是done()方法的回调函数,第二个参数是fail()方法的回调方法。如果then()只有一个参数,那么等同于done()。

  (8)deferred.reject()

这个方法与deferred.resolve()正好相反,调用后将deferred对象的运行状态变为”已失败”,从而立即触发fail()方法。

  (9)deferred.always()

这个方法也是用来指定回调函数的,它的作用是,不管调用的是deferred.resolve()还是deferred.reject(),最后总是执行。

  $.ajax( “test.html” )

  .always( function() { alert(“已执行!”);} );

(完)