前端页面的性能优化
减少HTTP请求
文件合并
合并css或js文件使要下载的文件数减少
css sprites
使用图片精灵将大量的背景图片整合到一张图片,然后用background-image
和background-position
控制背景图片的位置定位到要显示的图片,适用于数量多,体积小的图表等图片。
行内图片(base64格式)
将图片转化为base64
格式直接嵌入html
内部
服务端设计配置
跨域分离组件
分离组件可以最大化并行下载,但要确保只用不超过2-4个域,因为存在DNS查找的代价。例如,可以把HTML和动态内容部署在www.example.org
,而把静态组件分离到static1.example.org
和static2.example.org
。
减少DNS查询(较少主机数量)
当在浏览器导航栏中输入网站地址时,浏览器会按照浏览器DNS缓存、计算机DNS缓存、DNS服务器的顺序以此查找与域名相映射的IP。
DNS查找数与页面主机数相同,较少主机数就可以较少DNS查找数,但是减少主机数也减少了页面组件能够并行下载的数量。因此找到一个平衡值可以兼顾两者的需要。2-4个主机名是同时减少DNS查找和允许高并发下载的折中方案。
避免重定向
重定向会拖慢用户体验,在用户和HTML文档之间插入重定向会延迟页面上的所有东西,页面无法渲染,组件也无法下载,直到新的文档被送到浏览器。
压缩组件资源
支持压缩的Accept-Encoding HTTP请求头。
Content-Encoding响应头
尽可能多地用gzip压缩减少资源体积。
使用CDN(内容分发网络)
内容分发网络(CDN)是一组分散在不同地理位置的web服务器,用来给用户更高效地发送内容。
使用缓存
使用缓存可以避免重复下载资源,加快响应时间
设置响应头Expires
Expires 头指定了一个日期/时间, 在这个日期/时间之后,HTTP响应被认为是过时的;在这之前的时间都可以使用缓存。
通用消息头cache-control(单项指令,意味着在响应里设置的指令,在请求中不用包含相同的指令。)
可以指定多项配置控制缓存是否可用、以及可用时间、或者根据验证器判断缓存是否可用。可以覆盖expires的设置。
响应头Last-Modified/请求头If-Modified-Since
由于精确度比 ETag 要低,所以这是一个备用机制。指定服务器资源的下次更新时间,在这之前都可以使用缓存。
响应头ETag/请求头If-None-Match
服务器接收到请求时根据If-None-Match的验证码判断资源是否已改变,如果给定URL中的资源更改,则一定要生成新的Etag值,然后返回给客户端。
前端设计配置
延迟加载组件
JavaScript是分隔onload(资源加载完毕)事件之前和之后的一个理想选择。例如,如果有JavaScript代码和支持拖放以及动画的库,这些都可以先等会儿,因为拖放元素是在页面最初渲染之后的。其它可以延迟加载的部分包括隐藏内容(在某个交互动作之后才出现的内容)和折叠的图片。
预加载组件
通过预加载组件可以充分利用浏览器空闲的时间来请求将来会用到的组件(图片,样式和脚本)。用户访问下一页的时候,大部分组件都已经在缓存里了,所以在用户看来页面会加载得更快。
减少DOM元素数量
一个复杂的页面意味着要下载更多的字节,dom数的生成也会受到影响,而且用JavaScript访问DOM也会更慢。
尽量少使用iframe
-
代价高昂,即使是空白的iframe
-
阻塞页面加载
-
非语义
把JavaScript和CSS放到外面
用外部文件可以让页面更快,因为JavaScript和CSS文件会被缓存在浏览器。
HTML文档中的行内JavaScript和CSS在每次请求该HTML文档的时候都会重新下载。
这样做减少了所需的HTTP请求数,但增加了HTML文档的大小。 而且另一方面,如果JavaScript和CSS在外部文件中,并且已经被浏览器缓存起来了,那么我们就成功地把HTML文档变小了,而且还没有增加HTTP请求数。
压缩JavaScript和CSS
从代码中去除不必要的字符以减少大小,从而提升加载速度。代码最小化就是去掉所有注释和不必要的空白字符(空格,换行和tab)
对Ajax用GET请求
浏览器的POST请求是通过一个两步的过程来实现的:先发送HTTP头,在发送数据。所以最好用GET请求,它只需要发送一个TCP报文(除非cookie特别多)。
css部分
把样式表放在顶部
把样式表放到文档的HEAD部分能让页面看起来加载地更快。这是因为把样式表放在head里能让页面逐步渲染。
避免使用CSS表达式
用CSS表达式动态设置CSS属性,是一种强大又危险的方式。从IE5开始支持,但从IE8起就不推荐使用了。
选择<link>
舍弃@import
@import的导入方式相当于在文档底部引入css文件,不利于页面的加载体验
js部分
去除重复脚本
重复脚本会创建不必要的HTTP请求,执行无用的JavaScript代码,而影响页面性能。
尽量减少DOM访问
用JavaScript访问DOM元素是很慢的,所以,为了让页面反应更迅速,应该:
-
缓存已访问过的元素的索引
-
先“离线”更新节点,再把它们添到DOM树上
-
避免用JavaScript修复布局问题
使用事件委托
有时候感觉页面反映不够灵敏,是因为有太多频繁执行的事件处理器被添加到了DOM树的不同元素上。事件能够冒泡,所以可以捕获事件并得知哪个按钮是事件源。
把脚本放在底部
脚本会阻塞并行下载,HTTP/1.1官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个主机名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同主机名下的。
但是如果脚本是用document.write插入到页面内容中的,就没办法再往下移了。
用推迟(deferred)脚本,有DEFER属性的脚本意味着不能含有document.write,并且提示浏览器告诉他们可以继续渲染。
图片
优化选择图片
尝试把GIF格式转换成PNG格式,看看是否节省空间。在所有的PNG图片上运行pngcrush(或者其它PNG优化工具)
优化CSS Sprite
-
在Sprite图片中横向排列一般都比纵向排列的最终文件小
-
组合Sprite图片中的相似颜色可以保持低色数,最理想的是256色以下PNG8格式
-
“对移动端友好”,不要在Sprite图片中留下太大的空隙。虽然不会在很大程度上影响图片文件的大小,但这样做可以节省用户代理把图片解压成像素映射时消耗的内存。100×100的图片是1万个像素,而1000×1000的图片就是100万个像素了
尽量使用尺寸刚好满足需求的图片
不要因为在HTML中可以设置宽高而使用本不需要的大图。如果需要
<img width="100" height="100" src="mycat.jpg" alt="My Cat" />
那么图片本身(mycat.jpg)应该是100x100px的,而不是去缩小500x500px的图片。
用小的可缓存的favicon.ico(P.S. 收藏夹图标)
favicon.ico是放在服务器根目录的图片,它会带来一堆麻烦,因为即便你不管它,浏览器也会自动请求它,所以最好不要给一个404 Not Found响应。而且只要在同一个服务器上,每次请求它时都会发送cookie,此外这个图片还会干扰下载顺序,例如在IE中,当你在onload中请求额外组件时,将会先下载favicon。
避免图片src属性为空
图片src属性为空会导致浏览器向服务器发送另一个请求。
Cookie
给Cookie减肥
发送cookie也会影响性能,所以保证cookie尽可能的小,以最小化对用户响应时间的影响。
-
清除不必要的cookie
-
保证cookie尽可能小,以最小化对用户响应时间的影响
-
注意给cookie设置合适的域级别,以免影响其它子域
-
设置合适的有效期,更早的有效期或者none可以更快的删除cookie,提高用户响应时间
把组件放在不含cookie的域下
当浏览器发送对静态资源的请求时,cookie也会一起发送,而服务器根本不需要这些cookie。所以它们只会造成没有意义的网络通信量,应该确保对静态组件的请求不含cookie。可以创建一个子域,把所有的静态组件都部署在那儿。
有一点需要注意:如果不知道应该用example.org还是www.example.org作为主页,可以考虑一下cookie的影响。省略www的话,就只能把cookie写到*.example.org,所以因为性能原因最好用www子域,并且把cookie写到这个子域下。
www是一个主域的二级子域,但指向的还是主域。
移动端
保证所有组件都小于25K
这个限制是因为iPhone不能缓存大于25K的组件,注意这里指的是未压缩的大小。这就是为什么缩减内容本身也很重要,因为单纯的gzip可能不够。
把组件打包到一个复合文档里
把各个组件打包成一个像有附件的电子邮件一样的复合文档里,可以用一个HTTP请求获取多个组件(记住一点:HTTP请求是代价高昂的)。用这种方式的时候,要先检查用户代理是否支持(iPhone就不支持)。