那么,其他的时间用于加载什么呢?确切的说,如下:
让我们使用一个工具去看看-Fiddler (http://www.fiddler2.com/fiddler2/)
首先打开fiddler,然后使用浏览器访问 www.microsoft.com
这时候我们可以看到fiddler监控到客户端与微软网站服务器之间的交互情况如下图:
注意fiddler 右边的选项卡,有一个timeline。载入default.asp话费了大概1s的时间。让我们全选这些行。再去看看timeline,如下图
这时候我们根据数据就可以证明前边的观点,对于某个网站来说,80%的时间是用于加载css/JS/image的。
对于http协议的理解是非常重要的,因为它定义了web 浏览器和 web 服务器如何交互。
对于这点来说,最重要的是text,它不是基于二进制的协议,而是基于text的。
以下是 http协议的内容。我十分推荐你们阅读它:http://tinyurl.com/8395lq
HttpRequest
我们使用fiddler观察一下我们访问微软的httprequest。
选中第一个记录。右边选项卡依次->Inspecotrs->Raw
我们简单分析,
Get指明了url和http的版本。
host指明了host的地址。
accept-language指明了浏览器使用的语言
accept-Encoding指明了是否可以使用对浏览器到服务器之间的数据进行压缩。
HttpResponse
下面我们来看看刚才我们请求的响应。
我在fiddler中选中的是第12行数据,选中右边选项卡->Inspecotrs->Raw
# | Result | Protocol | Host | URL | Body | Caching | Content-Type | Process | Comments | Custom |
---|---|---|---|---|---|---|---|---|---|---|
12 | 200 | HTTP | www.microsoft.com | /en-us/homepage/shared/core/2/js/js.ashx?& | 3 | private | text/javascript; charset=utf-8 | chrome:3856 |
Http/1/1 200 OK。是告诉大家,一切运行良好。 200是一种状态,如果遇到问题可能会是404,500等。
其他细节,大家可以自己查一下资料。
大家都可以明白。提升网站的性能,可以让用户更加满意。而这也能让我们省钱和赚钱。
使用更小的带宽
更少的服务器数量
增长的销售和流量
对于网站性能对流量和销售产生的影响请参见相关文章《web性能心理学》http://www.websiteoptimization.com/speed/tweak/psychology-web-performance/
如何减少http request呢?我们根据上边提到fiddler侦听到的http request 得知,好多次请求是去获取css,javascript,和image的。
首先我们先来看看一个网站:
它是一个普通的网站他可以使用jquery来弹出图片,我们用fiddler 来试试它。
我们可以看出。他包含了一些css文件,也使用了jquery。
让我们看看这个网站的另一个版本。
样子是一模一样的,我就不show图了。
让我们看看fiddler 又帮我们抓到了什么:
js和css文件都变成1个了。我们把上边的js文件合并成1个js文件。这样我们就减少了httprequest的次数。
2.发送尽可能少的数据
我们回到fiddler。查看第一个网站的jquery文件“jquery-1.6.2.js。
它的普通版本是236k。
第一个网站需要加载js的总大小是279k。
而第二个网站需要加载js的大小是50.8k。
我们做了什么呢?只是把js文件里的白空格去掉了,就是对js文件的压缩。
css文件也如此。在最后的product版本上,我们使用合并的文件可以减少httprequest次数。当然在debug的时候我们要保留空行增加代码的可读性。
关于压缩js的工具我们在网上可以找到很多,就不列举。
3.减少交互的次数(适当使用缓存)
让我们刷新一下第二个网站,并观看fiddler。我们可以发现,第二次加载至向服务器获取了default.aspx。
并没有重新加载js、css和图片。因为浏览器已经替我们缓存了那些文件。
上一章我讲了很多关于Fiddler的东西。其实有很多检测工具可以使用,如 Fiddler 、chrome、firebug、Network Monitor、IIS 和一些第三方的service。
首先我们还是先继续回顾一下fiddler的功能
Chrome 是google 开发的一个非常适合开发人员使用的浏览器。它同样可以测量一个网站的性能,
现在一个chrome浏览器,并且按F12。你可以看到很多开发人员选项。我们可以看到以下工具:
让我们试试他们都能干吗,功能可能一带而过,因为我们这节只关注性能相关的功能。
element :可以让我们观察当前页面包含哪些html元素。
Resources:引用哪些资源。
network 和timeline:功能类似fiddler。是关于http request 、response和timeline情况
profiles:可以收集三种profile。比如javascript 占用多少cpu。大家不防自己试试。
Audits 就更酷了。它可以为你的站点提出优化建议。就像下图。他提供了一些建议。开启gzip压缩,使用浏览器缓存移除没有使用到的css引用等。这个页面就是我写博客时候用的。所以,咱们的院子还可以提高性能:)
由于篇幅有限,我这里就不详细介绍了,功能上和chrome差不多。下载一个firefox浏览器之后,安装firebug插件就可以使用了。呼出也是F12(让我想起了小时候的传奇外挂。。)
配上个图:
以下是获得这个免费工具的地址:http://www.microsoft.com/en-us/download/details.aspx?id=4865
看到这的朋友们就下载下来试试吧。
首先创建一个新的Capture-》工具栏里的”New Capture“。然后点击上边绿色三角 start。切换到IE浏览器。访问www.microsoft.com。然后切换回来点击stop。
我们可以发现有很多信息。包含了很多协议。现在我们添加一个过滤器:http
第一条信息居然是搜狐mail。不要紧,一定是它定期去发送http request获取mail信息了。
我们可以看到location实际访问的***/mail/check。是的,我们想对了。它就是去检查邮件啦。
我在这里只是想抛砖引玉。如果你对Microsoft Network Monitor感兴趣。请参见:http://en.wikipedia.org/wiki/Microsoft_Network_Monitor
IIS对于性能测量方面能为我们提供2个feature:
我们可以通过IIS的日志文件进行我们的性能分析。首先打开IIS->选定站点->logging(日志)
点击选择字段。并且勾选上所用时间以及你感兴趣的字段。
点击确定之后,每当有request来到你的IIS服务器。IIS都会为你记录一份详尽的日志。
LogParser 是一个命令行工具,可以通过SQL 语句对日志进行分析统计。可以分析IIS日志,还可以分析系统事件日志,CSV,XML等格式日志
基本的用法如下:
LogParser –i:输入文件的格式 –o:输出格式 “SQL语句”
例如下面的例子是用Log Parser统计访问整个IIS站点次数最多的IP:
logparser.exe -i:IISW3C SELECT TOP 25 cs-uri-stem as Url, COUNT(*) As Hits FROM c:\inetpub\logs\LogFiles\W3SVC1\* GROUP BY cs-uri-stem ORDER By Hits DESC
如果你对logparser 感兴趣。可以再去读读 这篇文章:http://blogs.msdn.com/b/carlosag/archive/2010/03/25/analyze-your-iis-log-files-favorite-log-parser-queries.aspx
Keynote http://www.keynote.com/ ,Gomez(收费的)
在这一章节,我们的主题聚焦在基础设施建设上。
我们前边提到过,性能规则中的一条就是在服务器和浏览器之间传输的数据越少越好。介于此规则,我们可以使用一个比较成熟的技术:Http Compression。
IIS7 对 compression 的支持
如果你对IIS 使用compression 感兴趣。可以参见:http://weblogs.asp.net/owscott/archive/2004/01/12/57916.aspx
打开IIS。选中一个你的网站。在右边选项卡里选择压缩(compression)
也许有的朋友会发现,动态压缩是灰色的。其实是我们没安装动态压缩模块。我使用的是win7。安装方法如下:
控制面板-》程序-》开启或关闭windows功能-》Internet 信息服务-》万维网服务-》性能功能(猥琐)-》动态内容压缩
如果是win server版本的朋友需要:
现在我们还用第一章里用到的那个网站做测试。打开fiddler。
记下每个文件的大小。返回到IIS,开启动态压缩和静态压缩。现在IIS 再接收到请求我的js和css文件时。它先会判断是否已经压缩过呗请求的文件。如果没有它会进行压缩,并且存储到某一个目录。其他用户同样请求相同的文件时,它直接获取压缩过的文件即可。
现在我们回到fiddler看看结果吧。
jquery 文件从236K被压缩到90k。其他js和css文件也都受到相应的压缩。
现在我们再使用上一章的另一把利器microsoft network monitor观察压缩前和压缩后 来看看发生了什么变化。
压缩前:
压缩后:
非常容易使用 MS Network monitor 对比出。压缩前后,frame的数目明显的减少了,从40条减少到9条。
由于95%以上的请求都会被询问是否启用compression。所以主流的浏览器都支持compression。
启用compression会占用少许的cpu。IIS7 对这一块做了优化。
为了确保压缩没有使CPU超载,IIS7每30秒计算平均CPU利用率。当CPU利用率超过一个限制时,它会自动关闭压缩。当CPU利用率低于限制时, 它会重新启用压缩。
限制的默认值是:
关闭压缩 | 重启压缩 | |
动态文件 | 90% | 50% |
静态文件 | 100% | 50% |
注意这意味着如果服务器上的CPU一直在50%以上,但偶然高于90%,动态文件压缩会被关闭,但再也不会重新开启了。
可以通过修改applicationHost.config文件修改这些限制,通常它在C:\Windows\System32\inetsrv\config文件夹下。
找到<httpCompression>节。
2.修改httpdynamicCompressionEnableCpuUsage属性:<
httpCompression
dynamicCompressionEnableCpuUsage
=
"70"
.... >
3.重启IIS。
回顾一下我们第一张讲过的性能规则。有一条是尽可能不经常地传输数据。
一个用户访问我网站的首页,他会得到我的js,css和图片等文件。浏览器则替他保存到本地的缓存中。过了几天用户又来访问我的网站了。服务器还会看看浏览器缓存中有木有他要的文件。如果有的话,它会告诉server。我有这个文件。但是我想知道它的版本是不是最新的。服务器会看看这个文件到底改没改。如果改了,服务器会发送新的文件。如果没,服务器会返回给浏览器状态码304。涛声依旧。
304.没改。
利用浏览器缓存:
打开IIS。选中你的站点。选中scripts文件夹(装js的地方。如果有的话)在视图选项卡里找到HTTP 响应标头并进入。
右上角,设置常用标头-》使web内容过期。我们设置5天吧。这时候访问我们的网站。使用fiddler 观察结果如下:
那个max-age 我们算算 。正好是5天:)现在我们再打开IE。internet选项-》浏览历史记录-》设置-》查看文件
找到我们的js文件。查看属性,8月7号过期,正好5天:)
另一个对于提高网站性能有效的办法就是使用CDN了。
CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。
在这里我只做简单介绍,需要了解更详细信息,请参见:http://en.wikipedia.org/wiki/Content_delivery_network
看到这里读者肯定会说我屌丝了。不解释还废话那么多干什么?CDN都是大公司用的和我们有关系么?
下面我来讲讲我们可以利用到的CDN:
JQuery是现在最流行的js library之一。google、microsoft、jquery.com都免费host了jquery库在它们的cdn上。请看下图:
我在这里可以使用我们自己的服务器上的jquery文件。也可以选择从google、微软和jquery官网的cnd来读。即可以给自己服务器减少压力。也可以利用cnd加快读取速度。
什么是ETags?Etag的全称是 entity tag。ETag实际上是一个hash+changeNumber组成的值。hash由文件内容生成。IIS7中changeNumber默认是0;
本章前边内容提到,我们通过设置内容过期,利用浏览器缓存达到性能优化的效果,会使用expires headers告诉浏览器,不用再发送条件GET请求给服务器啦,直接用缓存里面的数据就可以啦,从而加快访问速度。
Etags 使用过程如下:
从此看来Etag有可能会误导浏览器,让浏览器忽略缓存重复下载相同的文件。
我们试着从删除ETAG。
先看看没删除之前ETAG长什么样?
using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary> /// Summary description for ETagRemoveModule /// </summary> public class ETagRemoveModule : System.Web.IHttpModule { public ETagRemoveModule() { // // TODO: Add constructor logic here // } public void Dispose() { } public void Init(HttpApplication context) { context.EndRequest += new EventHandler(HandlerEndRequest); } public void HandlerEndRequest(Object sender, EventArgs e) { System.Web.HttpContext.Current.Response.Headers.Remove("ETag"); } }
<system.webServer> <modules> <add name="ETagRemoveModule.cs" type="ETagRemoveModule"/> </modules> </system.webServer>
ETags就没啦:)
我们使用fiddler 可以看到,http response header 包含了很多信息。
但是有些信息是没必要展示给用户看的。比如我们使用了.netframework 4.0.我们使用IIS7.5。
首先它是多余的信息。其次它也有可能被一些骇客利用。
所以我们修改一下我们的代码:
public void HandlerEndRequest(Object sender, EventArgs e) { HttpResponse oResponse = System.Web.HttpContext.Current.Response; if (null != oResponse) { oResponse.Headers.Remove("X-AspNet-Version"); oResponse.Headers.Remove("Server"); oResponse.Headers.Remove("ETag"); } }
现在我们的header干净多了,也安全多了。
在这一章,我们会聚焦在前端性能:
几乎所有的CSS和Javascript 都应该放在外部文件
把css 和 js 文件放到外部文件的确可以让页面看的更加清爽,同时减小了页面本身的尺寸。
在外部的文件可重用性更高,例如你可以在一个css文件中定义整体布局。并且让每个页面的元素都遵从它。
在上一节中,我们提到了浏览器过期的重要性,所以在外部引用css和js文件也是非常重要的。
最后是可读性,有超过50%的人遇到过混乱的页面。里边夹杂着html、js、css 甚至还有c#code。这样的代码的可读性和维护性都差到极点了。
Css 和 javascript 的迷你化与合并是一种减少 httprequest 和传输数据量 的行之有效的方式。
1.找到Visual studio Project File(.csporj)
2.修改一个.cs文件,确保项目文件可以重新编译(如果我们只是修改js和css文件,项目不会重新编译)
3.使用msbuild Extension Pack(http://msbuildextensionpackcodeplex.com)
4.通过bin目录下webform程序集得到版本号。
5.使用Msbuild ajaxmodifier 去迷你化js和css文件。
6.使用Msbuild 去合并迷你化之后的文件。
7.注意文件以前的引用顺序。保持以前的顺序。
8.使用debug symbol vaule去确定是否在release 模式,为新的release build 引用新的合并过的文件。
主页快了46%
为了贴切描述这一过程,一下是proj文件的关键code。为了便于大家理解,我在本章的结尾放了一个完整的代码示例。我们需要安装msbuild 和 它的扩展 ajaxmodifier
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets.--> <Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\ajaxmin.tasks" /> <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks" /> <Target Name="BeforeBuild"> <ItemGroup> <GeneratedCSSJS Include="client/combined.*.css" /> <GeneratedCSSJS Include="client/combined.*.js" /> </ItemGroup> <Delete Files="@(GeneratedCSSJS)" /> </Target> <Target Name="AfterBuild"> <!--"Touch" a .cs file to force a rebuild so get a new version number even when only change .css or js files--> <Exec Command="ATTRIB -R code/forceRebuild.cs" /> <Touch Files="code/forceRebuild.cs" /> <Exec Command="ATTRIB +R code/forceRebuild.cs" /> <MSBuild.ExtensionPack.Framework.Assembly TaskAction="GetInfo" NetAssembly="$(OutputPath)\MsBuildUsage.dll"> <Output TaskParameter="OutputItems" ItemName="Info" /> </MSBuild.ExtensionPack.Framework.Assembly> <Message Text="Version:%(Info.AssemblyVersion)" Importance="high" /> <!--css file that need minimizing--> <ItemGroup> <CSSMin Include="content\Site.css" /> </ItemGroup> <!--css file to combine--> <ItemGroup> <CSSCat Include="content\site.min.css" /> </ItemGroup> <!--js file that need minimizing--> <ItemGroup> <JSMin Include="Scripts\jquery-1.5.1.js"/> <JSMin Include="Scripts\MicrosoftMvcAjax.js"/> </ItemGroup> <!--js file to combine--> <ItemGroup> <JSCat Include="Scripts\jquery-1.5.1.min.js"/> <JSCat Include="Scripts\MicrosoftMvcAjax.min.js"/> </ItemGroup> <!--Actual minimization and combine tasks--> <Message Text="minimization and combine js and css files..." Importance="high" /> <AjaxMin JsSourceFiles="@(JSMin)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".min.js" CssSourceFiles="@(CssMin)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" /> <Message Text="Concatinating js and css files..." Importance="high" /> <ReadLinesFromFile File="%(JSCat.Identity)"> <Output TaskParameter="Lines" ItemName="JSLines" /> </ReadLinesFromFile> <WriteLinesToFile File="client/combined.%(Info.AssemblyVersion).min.js" Lines="@(JSLines)" OverWrite="true" /> <ReadLinesFromFile File="%(CSSCat.Identity)"> <Output TaskParameter="Lines" ItemName="CSSLines" /> </ReadLinesFromFile> <WriteLinesToFile File="client/combined.%(Info.AssemblyVersion).min.css" Lines="@(CSSLines)" OverWrite="true" /> <!--Include the combined files temporarily in project so publish moves them--> <ItemGroup> <Content Include="client/combined.%(Info.AssemblyVersion).min.js" /> <Content Include="client/combined.%(Info.AssemblyVersion).min.css" /> </ItemGroup> </Target>
看看结果,我的proj里多了2个文件。我们在引用这两个文件时候只需要拼接出版本号即可。
我们平时接触到的图片大概分以下几种:
如果我们不能确定用哪种格式的图片,我们需要提供3种不同格式的相同图片,并且比较它们的质量和图片占用空间。
在这里我主要讲一下JEPG的压缩。我的想法是缩小50%的占用空间,看看它的质量如何?
【图片优化器】
下图是我使用了 PaintNet 和Smushit优化过的图片。原图是右边的,大小32K。PaintNet压缩50%后为左上图。下图是使用Smushit去掉无用的元数据。大小30K。
Css拼合器是一种合并图片的工具。说它是一种,就是有很多工具可以实现这个功能。
我们可以访问:http://spritegen.website-performance.org/ 去使用它。
【try it】
我去人人网主页选择了3张图片,使用压缩工具把它们打包,并且上传。
点击了最下边生成拼合图片之后。可以看到上方多了3行css 规则:
.sprite-rrdesk{ background-position: 0 0; width: 75px; height: 75px; } .sprite-rrgame{ background-position: 0 -125px; width: 75px; height: 75px; } .sprite-rrmusic{ background-position: 0 -250px; width: 75px; height: 75px; }
让我们看看合并之后的图片:
在项目中使用的时候我们先引用css,在html里只需要这样就可以啦:
<span class = "sprite-rrgame"> <span>
msbuild demo的源代码:
http://files.cnblogs.com/techborther/MsBuildUsage.7z
【msbuild 参考】 :http://msdn.microsoft.com/zh-cn/library/0k6kkbsd.aspx