高性能WEB开发

  新产品为了效果,做的比较炫,用了很多的图片和JS,所以前端的性能是很大的问题,分篇记录前端性能优化的一些小经验。

  第一篇:HTTP服务器

  因tomcat处理静态资源的速度比较慢,所以首先想到的就是把所有静态资源(JS,CSS,image,swf)提到单独的服务器,用更加快速的HTTP服务器,这里选择了nginx 了,nginx相比apache,更加轻量级,配置更加简单,而且nginx不仅仅是高性能的HTTP服务器,还是高性能的反向代理服务器

  目前很多大型网站都使用了nginx,新浪、网易、QQ等都使用了nginx,说明nginx的稳定性和性能还是非常不错的。

  1. nginx 安装(linux)

   http://nginx.org/en/download.html 下载最新稳定版本

  根据自己需要的功能先下载对应模板,这里下载了下面几个模块:

      openssl-0.9.8l,zlib-1.2.3,pcre-8.00

  编译安装nginx:

./configure

--without-http_rewrite_module

--with-http_ssl_module

--with-openssl=../../lib/openssl-
0.9.8l

--with-zlib=../../lib/zlib-
1.2.3

--with-pcre=../../lib/pcre-
8.00

--prefix=/usr/local/nginx

make

make install

WEB性能测试工具主要分为三种,一种是测试页面资源加载速度的,一种是测试页面加载完毕后页面呈现、JS操作速度的,还有一种是总体上对页面进行评价分析,下面分别对这些工具进行介绍,如果谁有更好的工具也请一起分享下。

  Firebug:

  Firebug 是firefox中最为经典的开发工具,可以监控请求头,响应头,显示资源加载瀑布图:

  HttpWatch  :

  httpwatch 功能类似firebug,可以监控请求头,响应头,显示资源加载瀑布图。但是httpwatch还能显示GZIP压缩信息,DNS查询,TCP链接信息,个人在监控http请求比较喜欢使用httpwatch,httpwatch包含IE和firefox插件。不过httpwatch专业版本是收费的,免费版本有些功能限制。 


  DynaTrace's Ajax Edition:

  dynaTrace 是本人常使用的1个免费工具,该工具不但可以检测资源加载瀑布图,而且还能监控页面呈现时间,CPU花销,JS分析和执行时间,CSS解析时间的等。

  Speed Tracer:

  speed trace 是google chrome的1个插件,speed trace的优势点是用于监控JS的解析执行时间,还可以监控页面的重绘、回流,这个还是很强的(dynaTrace也能有这个功能)。   注:安装这个插件,需要安装 Google Chrome Developer Channel 版本,但是这个链接的地址在国内好像打不开,如果打不开,请大家直接到这个地址去下载:    

http://www.google.com/chrome/eula.html?extra=devchannel

  Page Speed :

  Page speed 是基于firebug的1个工具,主要可以对页面进行评分,总分100分,而且会显示对各项的改进意见,Page Speed也能检测到JS的解析时间。

  yslow :

  yslow跟pge speed一样是基于 firefox/firebug的插件,功能与page speed类似,对各种影响网站性能的因素进行评分,yslow是yahoo的工具,本人也一直在使用,推荐一下。

  webpagetest : 

  webpagetest 是1个在线进行性能测试的网站,在该网站输入你的url,就会生成1个url加载的时间瀑布图,对所有加载的资源(css,js,image等等)列出优化的清单,也是非常好用的工具。

  缩小图片大小

  当图片很多的时候,减少图片大小是提高下载速度最直接的方法。
  1. 使用PNG8代替GIF(非动画图片),因为PNG8在效果一样的情况,图片大小比GIF要小。

  2. 用fireworks处理PNG图片,在我们产品中很多PNG图片是美工直接用photoshop导出的,后来让美工用fireworks处理PNG(大概的方式是选择保存为PNG8,删除背景色)。处理后100K的图片大小基本减少了3/4,但图片质量也会有少许降低,要看自己是否能接受。

  3. 使用Smush.it(http://www.smushit.com/ysmush.it/) 压缩图片,Smush.it是YUI团队做1个在线压缩图片的网站,该网站在不影响原图片的质量下去掉图片中一些元数据,所以可以放心使用该网站进行压缩,但这个压缩比例也是比较有限的。

  合并图片和拆分图片

  1. CSS Sprites合并图片以减少请求数来提高性能大家都知道。但不要把图片合并太多,太多太大了,就会因为这1个图片影响这个页面的显示了。

  2. 有时候我们需要把1个大图片拆分成多个小图片,比如产品首页图片比较少,就1个很大的banner图片,因浏览器都可以并发下载图片,所以如果不拆分,只使用1个大图片的话,下载速度反而会比较慢。

  透明图片处理

  IE6不能显示透明的PNG图片,是很多开发人员特别头疼的事,分别介绍下几种方式的优缺点。

  1.使用AlphaImageLoader,IE6支持filter,使用下面的CSS代码,可以让IE6支持PNG

#some-element {
background
: url(image.png);
_background
: none;
_filter
:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png',
sizingMethod='crop')
;
}

 

  外部JS的阻塞下载

  所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。至到JS下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。

  有人会问:为什么JS不能像CSS、image一样并行下载了?这里需要简单介绍一下浏览器构造页面的原理,当浏览器从服务器接收到了HTML文档,并把HTML在内存中转换成DOM树,在转换的过程中如果发现某个节点(node)上引用了CSS或者 IMAGE,就会再发1个request去请求CSS或image,然后继续执行下面的转换,而不需要等待request的返回,当request返回后,只需要把返回的内容放入到DOM树中对应的位置就OK。但当引用了JS的时候,浏览器发送1个js request就会一直等待该request的返回。因为浏览器需要1个稳定的DOM树结构,而JS中很有可能有代码直接改变了DOM树结构,比如使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以就会阻塞其他的下载和呈现。

  阻塞下载图:下图是访问blogJava首页的时间瀑布图,可以看出来开始的2个image都是并行下载的,而后面的2个JS都是阻塞下载的(1个1个下载)。

  嵌入JS的阻塞下载

  嵌入JS是指直接写在HTML文档中的JS代码。上面说了引用外部的JS会阻塞其后的资源下载和其后的内容呈现,哪嵌入的JS又会是怎样阻塞的了,看下面的列2个代码:

 

代码
<div>
<ul>
<li>blogJava<span style="color: #800000;"/></li>
<li>CSDN<span style="color: #800000;"/></li>
<li>博客园<span style="color: #800000;"/></li>
<li>ABC<span style="color: #800000;"/></li>
<li>AAA<span style="color: #800000;"/></li>
</ul>
</div>
<script type="text/Javascript">
// 循环5秒钟
{ var n = Number(new Date());
var n2 = Number(new Date());
while((n2 - n) (6*1000)){
n2
= Number(new Date());
}
</script>
<div>
<ul>
<li>MSN</li>
<li>GOOGLE</li>
<li>YAHOO</li>
</ul>
</div>

  http请求头的数据量

 

  我们先分析下请求头,看看每次请求都带了那些额外的数据.下面是监控的google的请求头

 

代码
Host www.google.com.hk
User-Agent Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.2.3) Gecko/20100401
Firefox/3.6.3 GTBDFff GTB7.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language zh-cn,en-us;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Proxy-Connection keep-alive

 

  上一篇中我们说到了 如何减少请求数,这次说说如何减少请求、响应的数据量(即在网络中传输的数据量),减少传输的数据量不仅仅可以加快页面加载速度,更可以节约服务器带宽,为你剩不少钱(好像很多机房托管都是按流量算钱的)。

  GZIP压缩

  gzip是目前所有浏览器都支持的一种压缩格式,IE6需要SP1及以上才支持(别说你还在用IE5,~_~)。gzip可以说是最方便而且也是最大减少响应数据量的1种方法。

  说它方便,是因为你不需要为它写任何额外的代码,只需要在http服务器上加上配置都行了,现在主流的http 服务器都支持gzip,各种服务器的配置这里就不一一介绍(其实是我不知道怎么配),

  nginx的配置可以参考我这篇文章:www.blogJava.NET/BearRui/archive/2010/01/29/web_performance_server.html

  我们先看看gzip的压缩比率能达到多少,这里用jquery 1.4.2的min和src2个版本进行测试,使用nginx服务器,gzip压缩级别使用的是:

  注意看上图的红色部分,jquery src文件在启用gzip后大小减少了70%

  这张图片可以看出就算是已经压缩过min.js在启用gzip后大小也减少了65%。

  别对图片启用gzip

  在知道了gzip强大的压缩能力后,你是否想对服务器上的所有文件启用gzip了,先让我们看看图片中启用gzip后会是什么情况。

  hoho,1个gif图片经过gzip压缩后反而变大了???这是因为图片本来就是一种压缩格式,gzip不能再进行压缩,反而会添加1额外的头部信息,所以图片会变大。

  在测试过程中,发现jpg的图片经过gzip压缩后会变小,不知道为何,可能跟图片压缩方式有关。不过压缩比率也比较小,所以就算是jpg,建议也不要开启gzip压缩。

  比较适合启用gzip压缩的文件有如下这些:

  1. Javascript

  2. CSS

  3. HTML,xml

  4. plain text

  别乱用cookie
  现在几乎没有哪个网站不使用cookie了,可是该怎么使用cookie比较合适了,cookie有几个重要的属性:path(路径),domain(域),expires(过期时间)。浏览器就是根据这3个属性来判断在发送请求的时候是否需要带上这个cookie。

  cookie使用最好的方式,就是当请求的资源需要cookie的时候才带上该cookie。其他任何请求都不带上cookie。但事实上很多人在使用 cookie的时候已经习惯性的设置成:path=/ domain=.domain.com。这样的结果就是不管任何请求都会带上cookie,就算你是请求的图片(img.domain.com)、静态资源服务器(res.domain.com)这些根本不需要cookie的资源,浏览器照样会带上这些没用的cookie。咱们一起来看现实中的1个列子,博客园(www.cnblogs.com):

  先看看博客园的cookie是怎么设置的,下面是firefox查看博客园cookie的截图:
    

  cnblogs总共有5个cookie值,而且全部设置都是  path=/ domain=.cnblogs.com。知道了cookie的设置后,我们再来监控下博客园首页的请求,监控的统计信息如下:

  总请求数:39(其中图片22个,JS7个,css2个)。

  其中js、css、image 主要来自3个静态资源服务器: common.cnblogs.com , pic.cnblogs.com ,static.cnblogs.com

  再看其中1个请求图片(http://static.cnblogs.com/images/a4/banner_job.gif)的请求头:

Host static.cnblogs.com
User-Agent Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.2.3) Gecko/20100401
Firefox/3.6.3 GTBDFff GTB7.0
Accept image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language zh-cn,en-us;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Proxy-Connection keep-alive
Referer http://www.cnblogs.com/
Cookie __gads=ID=a15d7cb5c3413e56:T=1272278620:S=ALNI_MZNMr6_d_PCjgkJNJeEQXkmZ3bxTQ;
 __utma=226521935.1697566422.1272278366.1272278366.1272278366.1;
__utmb=226521935.2.10.1272278366; __utmc=226521935;
__utmz=226521935.1272278367.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)

 

  本篇文章主要讨论下目前JS,CSS 合并、压缩、缓存管理存在的一些问题,然后分享下自己项目中用到的1个处理方案,并提供1个实例下载。

  存在的问题:合并、压缩文件主要有2方面的问题:

  1. 每次发布的时候需要运行一下自己写的bat文件或者其他程序把文件按照自己的配置合并和压缩。

  2. 因生产环境和开发环境需要加载的文件不一样,生产环境为了需要加载合并、压缩后的文件,而开发环境为了修改、调试方便,需要加载非合并、压缩的文件,所以我们常常需要在JSP中类似与下面的判断代码:

 

代码
<c:if test="${env=='prod'}">
<script type="text/Javascript" src="/js/all.js"></script>
</c:if>
<c:if test="${env=='dev'}">
<script type="text/Javascript" src="/js/1.js"></script>
<script type="text/Javascript" src="/js/2.js"></script>
<script type="text/Javascript" src="/js/3.js"></script>
</c:if>

页面呈现流程

 

  在讨论页面重绘、回流之前。需要对页面的呈现流程有些了解,页面是怎么把html结合css等显示到浏览器上的,下面的流程图显示了浏览器对页面的呈现的处理流程。可能不同的浏览器略微会有些不同。但基本上都是类似的。

  1.  浏览器把获取到的html代码解析成1个Dom树,html中的每个tag都是Dom树中的1个节点,根节点就是我们常用的document对象 (<html> tag)。dom树就是我们用firebug或者IE Developer Toolbar等工具看到的html结构,里面包含了所有的html tag,包括display:none隐藏,还有用JS动态添加的元素等。

  2. 浏览器把所有样式(主要包括css和浏览器的样式设置)解析成样式结构体,在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式,而firefox会去掉_开头的样式。

  3、dom tree和样式结构体结合后构建呈现树(render tree),render tree有点类似于dom tree,但其实区别有很大,render tree能识别样式,render tree中每个node都有自己的style,而且render tree不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到 render tree中。注意 visibility:hidden隐藏的元素还是会包含到render tree中的,因为visibility:hidden 会影响布局(layout),会占有空间。根据css2的标准,render tree中的每个节点都称为box(Box dimensions),box所有属性:width,height,margin,padding,left,top,border等。

  4. 一旦render tree构建完毕后,浏览器就可以根据render tree来绘制页面了。

  回流与重绘

  1. 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(其实我觉得叫重新布局更简单明了些)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

  2. 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。

  注:从上面可以看出,回流必将引起重绘,而重绘不一定会引起回流。

  什么操作会引起重绘、回流

  其实任何对render tree中元素的操作都会引起回流或者重绘,比如:

  1. 添加、删除元素(回流+重绘)

  2. 隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)

  3. 移动元素,比如改变top,left(jquery的animate方法就是,改变top,left不一定会影响回流),或者移动元素到另外1个父元素中。(重绘+回流)

  4. 对style的操作(对不同的属性操作,影响不一样)

  5. 还有一种是用户的操作,比如改变浏览器大小,改变浏览器的字体大小等(回流+重绘)

  让我们看看下面的代码是如何影响回流和重绘的: 

 

代码
var s = document.body.style; 
s.padding
= "2px"; // 回流+重绘
s.border = "1px solid red"; // 再一次 回流+重绘 
s.color
= "blue"; // 再一次重绘
s.backgroundColor = "#ccc"; // 再一次 重绘 
s.fontSize
= "14px"; // 再一次 回流+重绘 
// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));

it知识库高性能WEB开发,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。