你遇到过性能很差的网页吗?
这种网页响应特别慢,占用大量的CPU和内存,浏览起来常常卡顿,页面的动画效果也不流畅。
你会有什么反应?可能大多数用户都会关掉这个网页,访问其他网站,作为一名开发者,如何才能提高性能呢?
一、网页生成流程
要理解网页性能为什么不好,就要了解网页的生成过程
网页的生成过程,大致可以分为五步:
- HTML代码转化为DOM
- CSS代码转化为CSSOM(CSS Object Model)
- 结合DOM和CSSOM,生成一颗渲染树(包含每个节点的视觉信息)
- 生成布局(layout),即将所有渲染树的所有节点进行平面合成
- 将布局绘制(paint)在屏幕上
前三步都比较快,耗时的是第四步和第五步
“生成布局”(flow)和“绘制”(paint)这两步,合称为“渲染”(render)
二、重排和重绘
网页生成的时候,至少会渲染一次。用户在访问的过程中,还会不断重新渲染
以下三种情况,会导致网页重新渲染
- 修改DOM
- 修改样式表
- 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)
重新渲染就需要重新生成布局和重新绘制。前者叫做“重排”(reflow),后者叫做“重绘”(repaint)。
需要注意的是,“重绘”不一定需要“重排”,比如改变某个网页元素的颜色,就只会触发“重绘”,不会触发“重排”,因为布局没有改变。但是,“重排”必然导致“重绘”,比如改变一个网页元素的位置,就会同时触发“重排”和“重绘”,因为布局改变了。
三、网页性能优化技巧
1. 内容优化
- 尽量减少HTTP请求:常见方法包括合并多个CSS文件和JavaScript文件,利用CSS Sprites整合图像,Image map(图像中不同的区域设置不同的链接),内联图象(使用 data: URL scheme 在实际的页面嵌入图像数据)等。
- 减少DNS查找
- 避免重定向
- 使Ajax可缓存
- 延迟加载组件:考虑哪些内容是页面呈现时所必需首先加载的、哪些内容和结构可以稍后再加载,根据这个优先级进行设定。
- 预加载组件:预加载是在浏览器空闲时请求将来可能会用到的页面内容(如图像、样式表和脚本)。当用户要访问下一个页面时,页面中的内容大部分已经加载到缓存中了,因此可以大大改善访问速度。
- 减少DOM元素数量:页面中存在大量DOM 元素,会导致JavaScript遍历DOM的效率变慢。
- 根据域名划分页面内容:把页面内容划分成若干部分可以使你最大限度地实现平行下载。但要确保你使用的域名数量在2个到4个之间(否则与第2条冲突)。
- 最小化iframe的数量:iframes 提供了一个简单的方式把一个网站的内容嵌入到另一个网站中。但其创建速度比其他包括JavaScript和CSS的DOM元素的创建慢了1-2个数量级。
- 避免404:HTTP请求时间消耗是很大的,因此使用HTTP请求来获得一个没有用处的响应(例如404没有找到页面)是完全没有必要的,它只会降低用户体验而不会有一点好处。
2. 服务器优化
- 使用内容分发网络(CDN):把你的网站内容分散到多个、处于不同地域位置的服务器上可以加快下载速度。
- 添加Expires或Cache-Control信息头:对于静态内容,可设置文件头过期时间Expires的值为“Never expire(永不过期)”;对于动态内容,可使用恰当的Cache-Control文件头来帮助浏览器进行有条件的请求。
- Gzip压缩
- 设置ETag:ETags(Entity tags,实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制。
- 提前刷新缓冲区:当用户请求一个页面时,服务器会花费200到500毫秒用于后台组织HTML文件。在这期间,浏览器会一直空闲等待数据返回。在PHP中,可以使用flush()方法,它允许你把已经编译的好的部分HTML响应文件先发送给浏览器,这时浏览器就会可以下载文件中的内容(脚本等)而后台同时处理剩余的HTML页面。
- 对Ajax请求使用GET方法:当使用XMLHttpRequest时,浏览器中的POST方法会首先发送文件头,然后才发送数据。因此使用GET最为恰当。
- 避免空的图像src
3. Cookie优化
- 减小cookie大小:去除不必要的coockie,并使coockie体积尽量小以减少对用户响应的影响
- 针对Web组件使用域名无关的Cookie:对静态组件的Cookie读取是一种浪费,使用另一个无Cookie的域名来存放静态组件是一个好方法,或者也可以在Cookie中只存放带www的域名。
4. CSS优化
- 将CSS代码放在HTML页面的顶部
- 避免使用CSS表达式:CSS表达式在执行时候的运算量非常大,会对页面性能产生大的影响
- 使用<link>来代替@import
- 避免使用Filters:IE独有属性AlphaImageLoader用于修正IE 7以下版本中PNG图片的半透明效果,但它的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。
5. JavaScript优化
- 将JavaScript脚本放在页面的底部
- 将JavaScript和CSS作为外部文件来引用:在实际应用中使用外部文件可以提高页面速度,因为JavaScript和CSS文件都能在浏览器中产生缓存。
- 缩小JavaScript和CSS
- 删除重复的脚本
- 最小化DOM的访问:使用JavaScript访问DOM元素比较慢
- 开发智能的事件处理程序
6. 图像优化
- 优化图片大小
- 通过CSS Sprites优化图片
- 不要在HTML中使用缩放图片
- favicon.ico要小而且可缓存
7. 针对移动优化
- 保持组件大小在25KB以下:主要是因为iPhone不能缓存大于25K的文件(注意这里指的是解压缩后的大小)。
- 将组件打包成为一个复合文档:把页面内容打包成复合文本就如同带有多附件的Email,它能够使你在一个HTTP请求中获取多个组件。
再补充几条~~
(1)先将元素设为display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。
(2)position属性为absolute或fixed的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。
(3)只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden的元素只对重绘有影响,不影响重排。