首次使用的时候在HTML中嵌入资源HTML的标准是使用链接来加载外部资源。这使得更容易在服务器上(或者在CDN上)操作更新这些资源,而不是在每个页面上修改更新这些资源。根据上文讨论的,这种模式也使得浏览器能从本地缓存而不是服务器上获取资源。 但是对还没有缓存到浏览器localStorage的资源来说,这种模式对网站的性能有负面的影响。一般来说,一个页面需要几十个单独的请求来获取资源从而渲染页面。所以说,从性能的角度来说,如果一个资源没有很高的被缓存的几率的话,最好把它嵌入到页面的HTML中(叫inlining),而不是使用链接外部。脚本和样式是支持内嵌到HTML中的,但是图片和其他的二进制资源其实也是可以通过内嵌包含base64编码的文本来嵌入到HTML中的。 内嵌的缺点是页面的大小会变得非常大,所以对于Web应用来说,关键的是能够跟踪分析这个资源什么时候需要从服务端获取,什么时候已经缓存到客户端了。另外,在第一次请求资源后必须能够使用代码在客户端缓存资源,因此,在移动设备上,使用HTML5 localStorage能很好地做到内嵌。 实现小贴士:平稳处理。由于不知道用户是否已经访问过这个页面了,所以需要网站有机制能生成不同版本的页面。
使用HTML5服务端发送事件Web应用已经使用了各种从服务器上轮询资源的方法来持续地更新页面。HTML5的EventSource对象和Server-Sent事件能通过浏览器端的JavaScript代码打开一个服务端连接客户端的单向通道。服务端可以使用这个写通道来发送数据,这样能节省了HTTP创建多个轮询请求的消耗。这种方式比HTML的WebSocket更高效。WebSocket的使用场景是,当有许多客户端和服务端的交互的时候(比如消息或者游戏),在全双工连接上建立一个双向通道。 实现小贴士:需要进一步考虑。这个技术是基于具体的技术实现的。如果你的网站当前是使用其他的Ajax或者Comet技术来轮询的,转变成Server-Sent 事件需要重构网站的Javascript代码。
消除重定向当用户在一个移动设备上访问桌面PC网站的时候,Web网站应用通常读取HTTP的user-agent头来判断这个用户是否是来自移动设备的。然后应用会发送带有空HTTP body和重定向HTTP地址头的HTTP 301(或者302)请求,把用户重定向到网站的移动版本上去。但是,这个额外的客户端和服务端的交互通常在移动网络上会消耗几百毫秒。因此,在原先的请求上传递移动的web页会比传递一个重定向的信息并让客户端再请求移动页面更快。 对于那些想要在移动设备上看桌面PC网站的用户来说,你可以在移动web页面上提供一个链接入口,这样也能同时表示你的网站是并不提倡这种行为的。 实现小贴士:虽然这个技术在理论上是简单的,但是实际上并不易于实施。由于有些m.sites是宿主在其他地方的,所以许多网站会选择重定向到一个不同的服务器上。有的网站则是会在重定向请求的时候种植上Cookie告诉Web应用这个用户是在使用移动设备。这种方法可能对web应用来说更容易控制。
减少资源负载大小问题。渲染小页面更快,获取小资源也更快。减小每个请求的大小通常不如减少页面请求个数那么显著地提高性能。但是,有些技术在性能方面,特别是在需要对带宽和处理器性能精打细算的移动设备环境下,仍然是能带来很大利益的。
压缩文本和图像诸如gzip这样的压缩技术,依靠增加服务端压缩和浏览器解压的步骤,来减少资源的负载。但是,一般来说,这些操作都是被高度优化过了。而且测试表明,压缩对网站还是起到优化性能的作用的。那些基于文本的响应,包括HTML,XML,JSON(Javascript Object Notation),Javascript,和CSS可以减少大约70%的大小。 浏览器在Accept-Encoding请求头中申明它的解压缩技术,并且当它们接收到服务端返回的Content-Encoding响应头标示的时候,就会按照这个响应头自动做解压操作。 实现小贴士:易于实现。如果设置正确的话,现在所有的Web服务器都支持压缩响应。但是,也有一些桌面PC的安全工具会将请求头中的Accept-Encoding头去掉,这样即使浏览器支持解压缩,用户也无法获取到压缩后的响应。
代码简化简化通常是使用在脚本和样式文件中,删除一些不必要的字符,比如空格,换行符,或者注释等。不需要暴露给外部的命名就可以被缩短为一个或者两个字符,比如变量名。合适的简化资源通常在客户端不需要做任何其他的处理,并且平均减少20%的资源大小。内嵌在HTML中的脚本和样式文件也是可以精简的。有很多很好的库来做精简化的操作,这些库一般也同时会提供合并多个文件这样减少请求数的服务。 简化带来的好处并不局限于减少带宽和延迟,对于那些移动设备上缓存无法保存的过大资源来说,也是很有改善的。Gzip在这个方面并没有任何帮助,因为资源是在被解压后才被缓存起来的。 实现小贴士:易于实现。Google的Closure Compiler已经难以置信地完成了理解和简化Javascript的工作。但是CSS的简化则没有那么容易,因为对不同浏览器来说有不同的CSS技术能迷惑CSS简化工具,然后让CSS简化后无法正常工作。必须要注意的是,已经有这样的案例了,即使只是删除了不必要的字符,简化工作也有可能破坏页面。所以当你应用简化技术之后,请做一下完整的功能测试工作。
调整图片大小图片通常是占用了Web页面加载的大部分网络资源,也占用了页面缓存的主要空间。小屏幕的移动设备提供了通过调整图片大小来加速传输和渲染图片资源的机会。如果用户只是在小的移动浏览器窗口中看图片的话,高分辨率的图片就会浪费带宽、处理时间和缓存空间。 为了加速页面渲染速度和减少带宽及内存消耗,可以动态地调整图片大小或者将图片替换为移动设备专用的更小的版本。不要依靠浏览器来将高分辨率的图片转换成小尺寸的图片,这样会浪费带宽。 另外一个方法是先尽快加载一个低分辨率的图片来渲染页面,在onload或者用户已经开始和页面交互以后将这些低分辨率的图片替换成为高分辨率的图片。 实现小贴士:特别应用在高度动态化的网站是有优势的。
使用HTML5和CSS 3.0来简化页面HTML5包括了一些新的结构元素,例如header,nav,article和footer。使用这些语义化的元素比传统的使用div和span标签能使得页面更简单和更容易解析。一个简单的页面更小加载更快,并且简单的DOM(Document Object Model)代表着更快的JavaScript执行效率。新的标签能很快地应用在包括移动端的新浏览器版本上,并且HTML5设计让那些不支持它的浏览器能平稳过渡使用新标签。 HTML5的一些表单元素提供了许多新属性来完成原本需要javascript来完成的功能。例如,新的placeholder属性用于显示在用户输入进入输入框之前显示的介绍性文字,autofocus属性用于标示哪个输入框应当被自动定位。 也有一些新的输入框元素能不用依靠Javascript就可以完成一些通用的需求。这些新的输入框类型包括像e-mail,URL,数字,范围,日期和时间这样需要复杂的用户交互和输入验证的元素。在移动浏览器上,当需要输入文本的时候,弹出的键盘通常是由特定的输入框类型来做选择的。不支持指定的输入类型的浏览器就会只显示一个文本框。 另外,只要浏览器支持内建的层次,圆角,阴影,动画,过渡和其他的图片效果,CSS 3.0就能帮助你创建轻便简易的页面了,而这些图片效果原先是需要加载图片才能完成的。这样,这些新特性就能加速页面渲染了。 有很多Web站点都提供哪些移动或者桌面浏览器支持哪项性能的更新说明。(例如:http://caniuse.com/ 和 mobilehtml5.org)。 实现小贴士:需要进一步考虑。人工地做这些改动是非常复杂和耗时的。如果你使用CMS,它可以帮你生成许多你不需要控制的HTML和CSS。
优化客户端的程序处理浏览器按照什么顺序来执行代码生成一个页面,和页面复杂性及JavaScript的技术选择,都对性能有很大的影响。特别在客户端相对较慢的CPUs和少内存的移动端中尤为明显。下面的章节提供一些策略来提升页面处理的性能。
延迟渲染”BELOW-THE-FOLD”内容可以确定的是如果我们将不可见区域的内容延迟加载,那么页面就会更快地展现在用户面前,这个区域叫做”below the fold”。为了减少页面加载后需要重新访问的内容,可以将图片替换为正确的高宽所标记的<img>标签。 实现小贴士:平稳处理。一些好的Javascript库可以用来处理这些below-the-fold 延迟加载的图像。^12
延迟读取和执行的脚本在一些移动设备上,解析Javascript代码的速度能达到100毫秒每千字节。许多脚本的库直到页面被渲染以后都是不需要的加载的。下载和解析这些脚本可以很安全地被推迟到onload事件之后来做。例如,一些需要用户交互的行为,比如托和拽,都不大可能在用户看到页面之前被调用。相同的逻辑也可以应用在脚本执行上面。尽量将脚本的执行延迟到onload事件之后,而不是在初始化页面中重要的可被用户看到的内容的时候执行。 这些延迟的脚本可能是你自己写的,更重要的是,也有可能是第三方的。对广告、社交媒体部件、或者分析的差劲的脚本优化会导致阻塞页面的渲染,会增加珍贵的加载时间。当然,你需要小心地评估诸如jquery这样为移动网站设计的大型脚本框架,特别当你仅仅只是使用这些框架中的一些对象的时候更要小心评估。 实现小贴士:平稳处理。许多第三方的框架现在提供延迟加载的异步版本的API。开发者只需要将原先的逻辑转化到这个异步版本。一些JavaScript要做延迟加载会有些复杂,因为在onload之后执行这些脚本需要注意很多注意事项。(例如,你有个脚本需要绑定到onload事件上,你需要做什么?如果你将脚本延迟到onload事件之后,就一定就会失去很多执行的时机。)
|