提升网页加载速度:网站性能优化的实用策略详解
一、前端优化
网站性能提升涉及多个层面,包括服务器配置、前后端程序等,以下将基于个人经验,分享网站性能提升的策略。标题中的“web2.0”指代本文侧重于中小型网站的性能提升,采用典型的LAMP架构。
首先,阐述前端优化。用户访问网页的等待时间,80%发生在浏览器前端,尤其是页面及元素(图片、CSS、JavaScript、Flash)的下载。相较繁琐的程序改进,前端优化往往能起到事半功倍的效果。雅虎公开了性能测试工具yslow,并发布了网站性能优化的十三条规则,建议下载并安装yslow,作为评估优化效果的工具。以下选取其中部分价值较高的方法进行说明:
对于首次访问网站的用户,尚未在浏览器缓存中存储内容的用户,我们可以:
1)降低页面访问产生的资源包大小(如package-info.php?package=APC)、使用TurckMMCache()、phpaccelebrator(),或购买ZendPerformanceSuite
2)将静态内容与动态内容分离处理
Apache功能全面但资源占用较大,内存消耗大,处理并行任务效率一般。在适当情况下,可使用轻量级webserver(如nginx)托管静态图片、样式表和JavaScript文件,提升处理速度,降低内存占用。
3)基于反向代理的前端访问负载均衡
当一台前端服务器无法应对用户访问时,通过前端机实现web访问的负载均衡是最快可行的方案。使用Apache的mod_proxy实现基于反向代理的负载均衡,推荐使用nginx作为代理服务器,处理速度较Apache更快。
4)应用缓存技术提升数据库性能,文件缓存和分布式缓存
数据库访问处理并发访问的能力是网站应用的关键瓶颈。在考虑使用主从结构和多farm构建服务器集群之前,应确保充分使用数据库查询的缓存。一些数据库类型(如mysql的innoDB)自身支持缓存,此外,可通过程序方法将常用查询通过文件或内存缓存起来。例如,使用php中的ob_start和文件读写函数实现文件缓存,或使用memcache技术通过分布式共享内存对数据库查询进行缓存,提高效率且易于扩展。
5)检测服务器运行状态,找出影响性能的瓶颈
系统优化没有一劳永逸的方法,需通过检测服务器运行状态及时发现影响性能的瓶颈和潜在问题。可编写脚本检测web服务的运行,或使用开源软件进行优化。
6)良好的扩展架构是稳定和性能的基础
一些技巧和窍门可帮助度过难关,但要想使网站具备应对大规模访问的能力,需从系统架构上进行彻底规划。许多前人分享了架构经验,使我们可以少走弯路。以下两篇文章有启发性:
-从LiveJournal后台发展看大规模网站性能优化方法
-Myspace的六次重构
最后,需关注程序编码和数据库结构对性能的影响。糟糕的循环语句、不合理的查询语句、设计不佳的数据表或索引表都可能导致应用程序运行速度降低。培养全局思考能力,养成良好的编程习惯,并了解数据库运行机制,是提高编程质量的基础。
如何对前端性能进行优化
前端开发代码优化、可维护性、浏览器兼容性是重要课题。以下从实际工程应用角度出发,列举常见的前端优化问题,并概述优化规则,涵盖前端大部分性能优化原则,许多更精细的优化方法均源于这些原则。
前端性能优化规则:
1. 减少HTTP请求次数
2. 尽量合并图片、CSS、JS,如将5个CSS文件合并为一个,只需发出一次HTTP请求,节省网络请求时间,加快页面加载。
3. 使用CDN
4. 避免空的src和href
5. 为文件头指定Expires
6. 使用gzip压缩内容
7. 将CSS放到顶部,使页面资源加载时优先渲染,提升用户体验。
网页资源的加载是按照从上至下的顺序进行的,因此将CSS置于页面顶端可以优先渲染页面,使用户感觉页面加载速度较快。
-
将JS放置于页面底部
在加载JS时,会对后续资源造成阻塞,必须等待JS加载完毕才能继续加载其他文件,因此将JS放置于页面底部最后加载。
-
避免使用CSS计算表达式
例如,以下CSS计算表达式的示例:
font-color: expression((new Date()).getHours()%3?“#FFFFFF":“#AAAAAA”);
此表达式会在页面上持续计算样式,影响页面性能。并且,CSS计算表达式仅被IE支持。
-
将CSS和JS存放在外部文件中
目的是缓存文件,可以参考原则4。但有时为了减少请求,也会直接写入页面中,需根据PV和IP的比例进行权衡。
-
权衡DNS查询次数
减少主机名可以节省响应时间。但同时,需要注意,减少主机可能会减少页面中并行下载的数量。IE浏览器在同一时刻只能从同一域名下载两个文件。当在一个页面显示多张图片时,IE用户的图片下载速度就会受到影响。因此新浪会使用多个二级域名来存放图片。
以下是新浪微博的图片域名,我们可以看到它有多个域名,这样可以确保这些不同域名能够同时下载图片,而无需排队。然而,如果使用的域名过多,响应时间可能会变慢,因为不同域名的响应时间可能不一致。
-
精简CSS和JS
这涉及到CSS和JS的压缩。例如,以下新浪的一个CSS文件示例,移除所有空格和换行符,以减小文件大小。现在的压缩工具有很多,基本主流的前端构建工具都能进行CSS和JS文件的压缩,如Grunt、Gulp等。
-
避免页面跳转
有一种现象可能会令人困惑,看起来似乎没有差别,但实际上进行了一次页面跳转。例如,当URL本应包含斜杠(/)却被忽略时。例如,当我们要访问http:// baidu.com时,实际上返回的是一个包含301代码的跳转,它指向的是http:// baidu.com/(注意末尾的斜杠)。在nginx服务器可以使用rewrite;Apache服务器中可以使用Alias或者mod_rewrite或者the DirectorySlash来避免。
另一种是不使用域名之间的跳转,例如访问http:// baidu.com/bbs跳转到http:// bbs.baidu.com/。那么可以通过使用Alias或者mod_rewirte建立CNAME(保存一个域名和另一个域名之间关系的DNS记录)来替代。
-
删除重复的JS和CSS
重复调用脚本,除了增加额外的HTTP请求外,多次运算也会浪费时间。在IE和Firefox中,不管脚本是否可缓存,它们都存在重复运算JavaScript的问题。
-
配置ETags
它用于判断浏览器缓存中的元素是否与服务器上的一致。比last-modified date更具有弹性,例如某个文件在1秒内修改了10次,Etag可以综合Inode(文件的索引节点(inode)数)、MTime(修改时间)和Size来精确地进行判断,避免UNIX记录MTime只能精确到秒的问题。在服务器集群使用时,可取后两个参数。使用ETags可以减少Web应用的带宽和负载。
-
可缓存的AJAX
异步请求同样会造成用户等待,因此在使用ajax请求时,要主动告诉浏览器如果该请求有缓存就去请求缓存内容。如下代码片段,cache:true就是显式地要求如果当前请求有缓存的话,直接使用缓存
$.ajax({ url:'url', dataType:"json", cache: true, success: function(son, status){}
-
使用GET来完成AJAX请求
当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。因此使用GET获取数据时更加有意义。
-
减少DOM元素数量
这是一门大学问,这里可以引申出一堆优化的细节。想要具体研究的可以看后面推荐书籍。总之,大原则是减少DOM数量,从而减少浏览器的解析负担。
-
避免返回404
例如,外链的CSS、JS文件出现问题返回404时,会破坏浏览器的并行加载。
-
减少Cookie的大小
Cookie中不要存放太多东西,因为每个请求都得带着它跑。
-
使用无cookie的域
例如CSS、js、图片等,客户端请求静态文件时,减少了Cookie的反复传输对主域名的影响。
-
不要使用滤镜
IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素(不仅仅是图片)它都会运算一次,增加了内存开支,因此它的问题是多方面的。
完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。
-
不要在HTML中缩放图片
例如,你需要的图片尺寸是50 50,那就不用一张500500的大尺寸图片,影响加载。
-
缩小favicon.ico并缓存