若是你的网站3秒钟没有响应,人们就会失去兴趣了。为了知足响应快这个愿望,须要一个不一样的方法在手机上进行分析,设计和测试。html
这篇文章将会对Johan Johansson在2013年4月提出" 怎样让你的网站在手机上也很快"的这种理念进行扩展。咱们将提出论证方法来确认人们在手机上与网站的交互方式和之前是不同的,特别是设计也是基于此理念的。咱们的目标不只仅是提升网站性能,并且也要增长客户收入的。web
咱们将关注手机两个特性,这两个特性短时间内也不会有变化:电池容量小,屏幕小。手机的通信要用无线电,但手机的电池很小,因此要很是谨慎的用电以防止把电用光。这样,若是无线电不用的时候就会迅速关掉,这样就增长了网页出现的时间。2G和3G无线技术须要2秒钟来创建HTTP连接。若是我接受“用户会在3秒后失去兴趣”的观点的话,那咱们的网站只有1秒来响应了。想一想这“黄金般的一秒”吧。算法
最大化利用这“黄金一秒”浏览器
在物理世界中,广告牌和杂志的内容都是根据媒介的大小和观看距离来定制的。在数字世界中,一个典型的中档智能手机拥有几乎6平方英寸大小的屏幕。15英寸的MacBook Pro电脑屏幕拥有超过100平方英寸的大小。这样,咱们不只能够经过减小发送到手机端的内容优化网站性能,并且能够优化业务流程来提升网站全部者的投资回报。缓存
本文的代码示例是由.NET提供。我已经在companion article文章中展现了用PHP, Java, C 和Python达到一样的效果。我在这篇文章的结尾会解释为何选用.NET。性能优化
网站设计者和开发者们经常想固然的认为用户应该用高带宽Wi-Fi和固网来链接。响应式网站设计(RWD)强制在不一样设备上(不论其性能好坏)显示相同的内容、导航和业务流程,限制了创新。服务器
确保咱们可以容易的进行性能测量,进行用户行为监控的基于不一样设备特性的解决方案以及低带宽设备网页访问优化都须要最大限度的利用这“黄金一秒”。cookie
现实移动带宽模拟测试是一个必不可少的移动Web性能测试。不少100美圆如下的廉价无线路由都提供了限制带宽功能,测试仅仅只涉及到了局域网内的客户端的上行和下行带宽限制功能。若是路由不支持这个功能话,那么试试用 DD-WRT(DD-WRT是一个开源升级固件,能够替代目前主流路由的默认操做系统)来限制带宽。网络
我用DD-WRT升级了Linksys E3000路由。路由升级的过程很是简单,DD-WRT官网上提供了完整的说明。
安装好DD-WRT后去到QoS菜单,启用带宽限制。设置上行和下行带宽的值,我习惯将下行带宽设置为256kbps,上行带宽设置为28kbps来模拟移动网络的平均带宽。架构
如今不管是以Wi-Fi或网线链接到路由器的设备的带宽都被人为的限制了。咱们能够监视带宽实际的使用状况。
虽然这种测试方法并无包括随机的掉线、可变带宽条件和由信号强弱引发的延迟等状况,可是比起你在快速、低延迟带宽下作的其余测试效果要好。在网站开发初期,这是一个在开发过程当中对Web性能进行非正式测试的简单的方法,可以确保你在正式测试过程当中不出现任何讨厌的问题。
管理顾问 Peter Drucker 曾经说过一句名言:“若是你没法测量某件事,你就没法管理它。”
持续根据设备特性(好比无线支持或屏幕大小)对用户查看的内容进行监控,或多或少将会有助于你识别手机上流行的内容和服务。也许你将看不到任何区别,可是除非你测量过,不然没法肯定。
一个全球化的快餐特许经营店须要建立针对移动终端的大屏幕互联网站点的优化版本。在建立第一个针对移动终端优化的互联网站点以前,执行分析以肯定大屏幕互联网站点的哪些项是小屏幕设备的用户能够访问的。主菜单、特卖品和分店查找是最受欢迎的,所以建立针对移动设备优化的互联网站点就集中在这些方面。
工做不能停留在此。接着的分析显示出分店查找是最受欢迎的。所以再次修改移动设备的主页以关注分店查找。继续的监视显示出多少访问者选择其余选项,而后依此不断改善地这个互联网站点,以确保用最简单可行的方法实现最受欢迎的栏目。
Google Analytics 提供了一些关于设备模型的信息,但它缺少咱们须要基于屏幕尺寸和输入方法做出明智决定的细节。幸运的是,一个全面的设备检测库(DDR)能够将此信息添加到现有日志文件中。下面的代码片断能够添加到 .NET网站中,参考51degrees.mobi(可经过 NuGet ) 获取屏幕的物理尺寸和输出到一个简单的CSV文件中。
// Write a log file containing the current time, and the screen // size of the requesting device in inches. File.AppendAllText( Path.Combine( AppDomain.CurrentDomain.BaseDirectory, String.Format( "App_Data\\Simple_Log_{0:yyyyMMdd}.csv", DateTime.UtcNow)), String.Format("{0:s},{1},{2},{3}\r\n", DateTime.UtcNow, Request.Path, Request.Browser["ScreenInchesWidth"], Request.Browser["ScreenInchesHeight"]));
第一行是处理请求的日期和时间。第二行是请求的页面。最后两行是设备屏幕的宽度和高度。抓取足够多的数据和平均屏幕的尺寸大小绘制出了下面的图表:
比较设备屏幕的平均大小超过20个月
分析能够缩小到具体的页面。有关设备的特性,操做系统和浏览器也能够被添加到列中。
相似的代码可使用PHP、Java、Python和其余环境语言。
有时,已有的Web页面不能按照上面的方式修改。在这样的状况下,DDR能够用来执行含有用户代理的日志日文的离线分析了。下面的.NET代码是一个实用的命令行程序,它解析空格分隔的日志文件,而后计算出日志所表示的请求以平方英尺为单位的平均屏幕尺寸。第一个参数是日志文件的位置,第二个参数是日志文件里用户代理所在列的索引。
using System; using FiftyOne.Foundation.Mobile.Detection.Binary; using System.IO; namespace ConsoleApplication { class Program { static void Main(string[] args) { // The number of devices read from the log file. int count = 0; // The column in the input file the user agent is held in. int column = int.Parse(args[1]); // Screen dimension variables. double total = 0, width, height, squareInches; // Create a provider to determine the device capabilities. var provider = Reader.Create("51Degrees.mobi.dat"); // Read each line of the log file provided in argument 0. // Assume the value at column 8 is the UserAgent string. using (var reader = File.OpenText(args[0])) { while(reader.EndOfStream == false) { var values = reader.ReadLine().Split(new[] { ' ' }); if (values.Length >= column) { // Get the device information based on the UserAgent. var device = provider.GetDeviceInfo( values[column - 1].Replace("+", " ")); if (device != null) { // Determine the screen dimensions in inches. double.TryParse( device.GetFirstPropertyValue("ScreenInchesWidth"), out width); double.TryParse( device.GetFirstPropertyValue("ScreenInchesHeight"), out height); squareInches = width * height; // If valid values are available (not a desktop/laptop) // then add the values to the results. if (squareInches > 0) { total += squareInches; count++; } } } } } Console.WriteLine( "Average screen size '{0:#.00}' square inches from '{1}' devices", total / count, count); Console.ReadKey(); } } }
分析日志文件很不许确,由于除了用户代理外的其余HTTP头都影响着检测结果。对Opera Mini和Opera 移动浏览器来讲尤为是这样的。在这两个浏览器里,第二个HTTP头,也就是名字为Device-Stock-UA的头经常用来提供标准用户代理里没有的有关物理硬件的信息。
监控使得咱们可以将不受欢迎的内容从主页中删除,以此提高更重要的内容或相关的内容的性能。删除的内容应该仍能够经过二级页面访问到——只是不放在首页,否则的话它们会消耗宝贵的带宽并下降性能体验。
那么,咱们怎样来建立一个独立的性能优化的移动网站呢?
我能理解为何RWD(响应web设计)从用户界面设计的角度来讲颇有意义。对于6平方英寸屏幕和10平方英寸屏幕,以及仅仅是须要进行改动的布局来讲,在内容,导航以及业务流程需求方面能够彻底一致,这实在是太棒了。
平均设备屏幕尺寸。
可是,在上述条件不为真或者对性能要求严格的时候有一个独立的移动网站 具备特别的意义。
独立的移动网站经常表现出一种不良的用户体验。经过给网站惩罚赋以较低的搜索引擎等级,Google如今投射出一缕曙光到这些普通的问题上。问题包括了将每一个桌面页发送到单独的移动主页,重定向到应用下载页,阻止用户访问大屏的网站,对全部带特定操做系统的设备以相同的方式处理。
这些糟糕的实现让人对这些概念有一个坏的印象。这里是一些简单又正确的作法。
下面的 .NETweb.config片断将把来自智能手机的第一个请求,重定向到网站上“Smartphone”部分指定的等价页面。 重要的是,查询字符串与页面名字在重定向的过程当中一直保持着。
1 <redirect firstRequestOnly="true" 2 mobileHomePageUrl="~/Mobile/Default.aspx" 3 timeout="20" 4 devicesFile="~/App_Data/Devices.dat" 5 mobilePagesRegex="/(Mobile|Smartphone)/" > 6 <locations> 7 <!--Send smartphones to an equivalent version of the original page, preserving the page name and query string.--> 8 <location name="smartphone" url="~/Smartphone/{0}" matchExpression="(?<=^\w+://.+/).+"> 9 <add property="IsSmartphone" matchExpression="true"/> 10 </location> 11 </locations> 12 </redirect>
在大多数情形,当重定向到替代页面时,若是愿意的话用户应当能够返回原始的页面;或许他们对网站的大屏幕版本更熟悉呢。firstRequestOnly属性保证了只有来自设备的第一次请求才被重定向。devicesFile属性是用来对不支持cookies的设备进行跟踪。timeout属性控制了在多长时间内该设备被记忆(为了重定向的目的)。
重定向系统还必须知道哪一个页面是针对哪一种设备设计的。mobilePagesRegex属性被应用到请求URLs。若是存在匹配,页面将不适用重定向。这阻止了无穷重定向的状况。
locations元素容许配置定义不一样的地址,以及相关的规则。这个例子将Smartphone目录插入到原始的URL。查询字符串和其余的URL信息在重定向过程当中一直保持。全部影响到请求上下文的信息必须被传送,以便用户得到他们指望的内容。
这个简单的方法使得一个搜索引擎友好的,兼容Google的,移动手机优化的网站,在传送的过程当中有良好的用户体验和优异的性能。这个过程的基础是DDR,它快速的,一致的,精确的提供了设备的信息。对于改变了移动手机浏览器设置到桌面模式的用户,重定向将不会发生。
云服务是给网站迅速增长特性的流行方法。可是它们跨越Internet的请求对性能带来损耗。若是忽略处理时间,咱们观察到由Amazon Web Service提供的云服务的数据传输有平均200毫秒的延时。
200毫秒是一个黄金秒的20%。所以,仔细考虑一下你使用的云服务在哪里,确保它们是异步调用的,以便在等待响应的过程当中其余处理能继续下去。它们应该避免关键路径上的活动,例如判别请求设备的信息。
紧随视频、图像以后,CSS和HTML占据了大量的Web流量。咱们须要优化全部这一切的方法。视频自己就是就能够写一篇文章,因此要等之后再说。
图像
流行的解决方案是同一张图像提供三个版本,并且当浏览器渲染页面的时候,使用JavaScript或者CSS选择最适合请求设备的那张图象。这是一个好的开始,不过管理同一图像的不一样版本倒是很痛苦的;图像历来都不是完美优化的,并且这种方法给有限CPU和电池电量的移动设备增长了进行图像大小调整的负担。
有一个更好的处理方法是使用图像优化器。能够经过Viusal Studio的集成开发环境把52Degrees.mobi的图像优化器增长到ASP.NET站点。下面的配置将自动增长到web.config里。
1 <handlers> 2 <add name="Image" verb="GET" path="P.axd" type="FiftyOne.Framework.Image.ImageHandler, FiftyOne.Framework" /> 3 </handlers>
上面的处理器告诉互联网信息服务(IIS)图像处理器应该处理资源P.axd的任何GET请求。
一旦web.config里启用这项,下面的ASP.NET代码将使用图像优化器从三种可能的资源-也就是分别为240,480和640像素宽的图像中肯定一个图像。
<mob:Image runat="server" ID="ImageBanner" CalculateSizeMode="ClientWidth" Style="clear: both; width: 100%"> <mob:AltImage ImageUrl="~/Images/Landscape240.png" /> <mob:AltImage ImageUrl="~/Images/Landscape480.png" /> <mob:AltImage ImageUrl="~/Images/Landscape640.png" /> </mob:Image>
当初始化显示图像的时候,服务器将发送一个白色的1x1像素的GIF显示在图像所在位置。下面就是生成的HTML
1 |
< img id = "B" src = "P.axd?i=E.gif&i=1" /> |
一旦页面装载完成,JavaScript用来算出最终显示图像所须要的真正的尺寸,而后向服务器请求一个大小明确的图像。通过JavaScript处理后,上面的HTML转换为:
1 |
< img id = "B" src = "P.axd?i=1&w=500" /> |
web.config中引用的图像处理器把i查询字符串关联到图像源,所以服务器上最适合的图像将用做调整的最初图像。w查询字符串参数指定了所请求图像的宽度。所以不须要提供多个图像;一个单独的图像几乎就能够了。 这种方法易于实现,并且结果是大小明确的图像。这样作不但减小了带宽,并且还减小了移动电话CPU的运行周期和电量。
整个牛津大辞典包括171476个单词。若是一个电脑用独有的二进制数字表明一个单词,而不是一个字母表的字母,大概须要用18比特(向上舍入大概3字节)。这代表压缩算法是十分有效的。
然而,HTML不是颇有效,由于它充满了用字符表明的元素、IDs,类,styles和Javascript,没有考虑到是不是人可读的。压缩能够减小这些,但仍是要有开销的。这就是为何流行的库都有人们读不懂的压缩版本。
在服务器发送给浏览器以前,一些与标记相关的单词还能够最小化,并且不会丢失任何这些单词的意义。看一个上面所示的图像的例子,ASP.NET里标准的HTML的图像元素的ID属性是ImageBanner。
<mob:Image runat="server" ID="ImageBanner" CalculateSizeMode="ClientWidth" Style="clear: both; width: 100%">
然而发送给浏览器的代码只使用B。对一个单独的元素来讲。这样的性能改进是微不足道的,然而,对一个含有数百个元素的复杂页面来讲,传送这样的页面会更快,并且浏览器将能更快地处理这一切。
图像例子生成的HTML看起来比较奇怪:
<img id="B" src="P.axd?i=1&w=500"/>
这段ASP.NET代码没有样式并且也没有为img元素设置CLASS属性。那么它的样式是怎么来的呢?
服务器端最小化过程当中将会肯定样式信息,而且为网页建立一个CSS文件,从而减少了HTML的大小。当HTML变化时,样式已经被缓存在浏览器中,不须要从新下载。CSS片断看起来就像这样:
#B{clear:both;width:100%;}
若是许多元素共享同一个样式,那么就要给这个CSS增长ID属性,这样它们就能够共享相同的信息。
还能够经过使用服务器端样式元素实如今多个元素和页面上共享样式信息。下面的代码扩展了前面图像例子,以此来讲明共享样式元素。
1 <mob:Style runat="server" ID="StyleBanner"> 2 <mob:Filter Style="clear: both; width: 100%"/> 3 </mob:Style> 4 5 <mob:Image runat="server" ID="ImageBanner" CalculateSizeMode="ClientWidth" StyleID="StyleBanner">
上面所示的图像优化和动态最小化HTML和CSS内容的技术和代码例子取决于页面渲染以后且服务器传送给浏览器以前更改的内容。这样的预处理技术在诸如ASP.NET的Web表格这样的结构里实现起来至关容易。
然而在基于脚本的好比PHP这样的架构里实现它们就很是复杂。正是因为这个缘由,而且为了保持一致性,这篇文章中的例子都是在.NET上的。咱们已经可以把这种技术应用到其余语言上,例子代码可在朋友博客里看到。
根据设备的能力,还能够对这个元素进行进一步扩展,使得能够应用其余样式,而且可在多个页面上优化样式表。 这种技术老是确保只传输必须的CSS,所以在对同一个页面的后续请求方面提升了性能,尤为是对HTML内容只有稍稍不一样的页面。
为了真正地优化性能,咱们须要考虑网站全部人的投资回报。监测设备特征的不一样是根本起始点。
而后咱们才能部署诸如利用分散的移动网站来分离或改变内容焦点的解决方案。咱们还能经过收紧缩小图像和HTML,移除jQuery,问询什么时候单独使用响应式网站设计(RWD),以及其它技术等使性能达到最高。固然,现有的技术也是相当重要的,例如配置缓存路径和压缩内容。
微调咱们的开发环境,来模拟真实世界的状况,这样也能够在整个开发过程当中得到对性能的更好的理解。
为了能让你更多地考虑性能,我已经设定好了一个寻找世界上最重型的网站的竞赛。寻找一个网页,它在移动电话上运行得很糟糕,并将其提交给竞赛。咱们会比较页面的份量,以及它是不是最重型的,你将所以而赢得1000美圆。与此同时,实现本文以及其余Smashing Magazine中的牛文中提到的技术,以确保你的网站在被咱们掂量其性能的时候不会出如今榜单之首!
从未有过比这更能提升你的网站性能的机会了。