前端性能优化----雅虎35条军规
前端性能优化—-雅虎 35 条军规
减少 HTTP 请求
80%的终端响应时间主要花费在前端,而这部分时间主要在下载网页中的图片,样式文件,脚本文件,flash 等资源。减少这些资源的数量就相应地减少了用于渲染页面的 HTT 请求数量。以下是一些具体的方法
简化设计
打包文件,将多个 JS 文件打包成一个 JS 文件,同样地,将多个 CSS 文件打包成一个 CSS 文件
使用 CSS Sprites,将页面中用到的背景小图标并合成一张图片,再使用 CSS 中的
bakground-image
和background-position
来显示所需图像部分图像映射,html 标签
内嵌图片,通过
data:URL scheme
内嵌
使用 CDN
在现有的网络中增加一层新的网络架构,将网站的内容发布到最接近用户的 Cache 服务器内,通过 DNS 负责均衡技术,判断用户来源就近访问 Cache 服务器上所需的内容。如此便可以减少数据在网络上传输的时间,提高速度
设置头文件过期时间或者缓存策略
- 静态内容:将 Expires 响应头设置为将来很远的时间,实现「永不过期」策略;
- 动态内容:设置合适的 Cache-Control 响应头,让浏览器有条件地发起请求。
Gzip
压缩Gzip
压缩通常可以减少 70%的响应大小,对某些文件更可能高达 90%,比Deflate
更高效主流 Web 服务器都有相应模块,而且绝大多数浏览器支持
gzip
解码图片和 PDF 文件不要使用
gzip
,它们本身已经压缩过,再使用gzip
压缩不仅浪费 CPU 资源,而且还可能增加文件体积从 HTTP/1.1 开始,web 客户端就有了支持压缩的 Accept-Encoding HTTP 请求头
把 CSS 文件放在顶部
把样式表放在
<head>
中可以让页面渐进渲染,尽早呈现视觉反馈,给用户加载速度很快的感觉。把 JS 文件放在底部
浏览器下载脚本时,会阻塞其他资源并行下载,即使是来自不同域名的资源。因此,最好将脚本放在底部,以提高页面加载速度。
一些特殊场景无法将脚本放到页面底部的,可以考虑
<script>
的以下属性:defer 属性;
HTML5 新增的
async
属性。
避免 CSS 表达式
CSS 表达式可以在 CSS 里执行 JavaScript,仅 IE5-IE7 支持,IE8 标准模式已经废弃。 CSS 表达式超出预期的频繁执行,页面滚动、鼠标移动时都会不断执行,带来很大的性能损耗。
将 JS 和 CSS 外链
外部 JavaScript 和 CSS 文件可以被浏览器缓存,在不同页面间重用,也能降低页面大小。
减少 DNS 查询
- 用户输入 URL 以后,浏览器首先要查询域名(hostname)对应服务器的 IP 地址,一般需要耗费 20-120 毫秒时间。DNS 查询完成之前,浏览器无法从服务器下载任何数据。
- 基于性能考虑,ISP、局域网、操作系统、浏览器都会有相应的 DNS 缓存机制。 IE 缓存 30 分钟,可以通过注册表中 DnsCacheTimeout 项设置;
Firefox 缓存 1 分钟,通过 network.dnsCacheExpiration 配置;
减小 JSS 和 CSS 体积
避免重定向
- 客户端收到服务器的重定向响应后,会根据响应头中 Location 的地址再次发送请求。重定向会影响用户体验,尤其是多次重定向时,用户在一段时间内看不到任何内容,只看到浏览器进度条一直在刷新。
- 最浪费的重定向经常发生、而且很容易被忽略:URL 末尾应该添加
/
但未添加。比如,访问http://astrology.yahoo.com/astrology
将被301
重定向到http://astrology.yahoo.com/astrology/
(注意末尾的 /)。如果使用
Apache,可以通过Alias
或mod_rewrite
或DirectorySlash
解决这个问题。 - 网站域名变更:
CNAME
结合Alias
或mod_rewrite
或者其他服务器类似功能实现跳转。
移除重复脚本
重复的脚本不仅产生不必要的 HTTP 请求,而且重复解析执行浪费时间和计算资源。
配置
ETags
ETags
通过文件版本标识,方便服务器判断请求的内容是否有更新,如果没有就响应 304,避免重新下载缓存 Ajax
有尚未过期的 Expires 或者 Cache-Control HTTP 头,那么之前的资源就可以从缓存中读出。必须通知浏览器,应该继续使用之前缓存的资源响应,还是去请求一个新的。可以通过给资源的 Ajax
URL 里添加一个表明用户资源最后修改时间的时间戳来实现。如果资源从上一次下载之后再没有被修改过,时间戳不变,资源就将从浏览器缓存中直接读出,从而避免一次额外的 HTTP 往返消耗。具体参考[3. 设置头文件过期时间或者缓存策略](#3.
设置头文件过期时间或者缓存策略)尽早释放缓冲
用户请求页面时,服务器通常需要花费 200 ~ 500 毫秒来组合 HTML 页面。在此期间,浏览器处于空闲、等待数据状态。使用 PHP 中的 flush()函数,可以发送部分已经准备好的
HTML 到浏览器,以便服务器还在忙于处理剩余页面时,浏览器可以提前开始获取资源。用 GET 方式进行 Ajax 请求
浏览器执行 POST 请求时分成两步,先发送 Http Header,再发送 data。而 GET 只使用一个 TCP 数据包(Http Header 与 data)发送数据,所以首选 GET 方法。
根据 HTTP 规范,GET 用于获取数据,POST 则用于向服务器发送数据,所以 Ajax 请求数据时使用 GET 更符合规范。
预加载组件
预先加载利用浏览器空闲时间请求将来要使用的资源,以便用户访问下一页面时更快地响应
延迟加载组件
页面初始加载时哪些内容是绝对必需的?不在答案之列的资源都可以延迟加载。比如:
- 非首屏使用的数据、样式、脚本、图片等
- 用户交互时才会显示的内容
减少 DOM 元素数量
从以下几个角度考虑移除不必要的标记:
- 是否还在使用表格布局?
- 塞进去更多的仅为了处理布局问题?也许有更好、更语义化的标记。
- 能通过伪元素实现的功能,就没必要添加额外元素,如清除浮动。 浏览器控制台中输入以下代码可以计算出页面中有多少 DOM 元素:
1
document.getElementsByTagName("*").length;
- 为什么不使用表格布局?
1
2
3+ 更多的标签,增加文件大小;
+ 不易维护,无法适应响应式设计;
+ 性能考量,默认的表格布局算法会产生大量重绘
跨域分离组件
浏览器一般会限制每个域的并行线程(一般为 6 个,甚至更少),使用不同的域名可以最大化下载线程,但注意保持在 2-4 个域名内,以避免 DNS 查询损耗。
减少
iframe
数量- 用
iframe
可以把一个 HTML 文档插入到父文档里,重要的是明白iframe
是如何工作的并高效地使用它。 iframe
的优点:1
2
3+ 可以用来加载速度较慢的第三方资源,如广告、徽章;
+ 可用作安全沙箱;
+ 可以并行下载脚本。iframe
的缺点:1
2
3
4+ 加载代价昂贵,即使是空的页面;
+ 阻塞页面 load 事件触发;
+ `iframe` 完全加载以后,父页面才会触发 load 事件。 Safari、Chrome 中通过 JavaScript 动态设置 iframe src 可以避免这个问题。
+ 缺乏语义。
不要出现 404 页面
HTTP 请求很昂贵,返回无效的响应(如 404 未找到)完全没必要,降低用户体验而且毫无益处
减小 Cookie
Cookie 被用于身份认证、个性化设置等诸多用途。Cookie 通过 HTTP 头在服务器和浏览器间来回传送,减少 Cookie 大小可以降低其对响应速度的影响。
1
2
3
4- 去除不必要的 Cookie;
- 尽量压缩 Cookie 大小;
- 注意设置 Cookie 的 domain 级别,如无必要,不要影响到 sub-domain;
- 设置合适的过期时间。对静态资源使用无 Cookie 的域名
静态资源一般无需使用 Cookie,可以把它们放在使用二级域名或者专门域名的无 Cookie 服务器上,降低 Cookie 传送的造成的流量浪费,提高响应速度。
较少 DOM 访问次数
JavaScript 操作操作 DOM 很慢,尤其是 DOM 节点很多时。
使用时应该注意:
1
2
3
4- 缓存已经访问过的元素;
- 使用DocumentFragment暂存DOM,整理好以后再插入DOM树;
- 操作className,而不是多次读写style;
- 避免使用JavaScript修复布局。开发高效的事件处理句柄
- 减少绑定事件监听的节点,如通过事件委托;
- 尽早处理事件,在 DOMContentLoaded 即可进行,不用等到 load 以后。
使用
<link>
而非@import避免使用过滤器
避免使用 AlphaImageLoader,可以使用 PNG8 替代
优化图片
优化 CSS Sprites
- 水平排列
Sprite
中的图片,垂直排列会增加图片大小; Sprite
中把颜色较近的组合在一起可以降低颜色数,理想状况是低于 256 色以适用 PNG8 格式;- 不要在
Sprite
的图像中间留有较大空隙。减少空隙虽然不太影响文件大小,但可以降低用户代理把图片解压为像素图的内存消耗,对移动设备更友好。
不要再 HTML 中伸缩图片
不要使用的 width、height 缩放图片,如果用到小图片,就使用相应大小的图片
缩小
favicon.ico
的大小并使用缓存Favicon.ico 一般存放在网站根目录下,无论是否在页面中设置,浏览器都会尝试请求这个文件。所以确保这个图标:
- 存在(避免 404);
- 尽量小,最好小于 1K;
- 设置较长的过期时间。
- 对于较新的浏览器,可以使用 PNG 格式的 favicon。
保证组件在 25K 以下
这个限制是因为 iPhone 不能缓存大于 25K(压缩前)的组件
将组件打包进一个多部分的文档中
把各个组件打包成一个像有附件的电子邮件一样的复合文档里,可以用一个 HTTP 请求获取多个组件(记住一点:HTTP 请求是代价高昂的)。用这种方式的时候,要先检查用户代理是否支持(iPhone 就不支持)
避免空的图像
src
属性- 虽然 src 属性为空字符串,但浏览器仍然会向服务器发起一个 HTTP 请求
- 空的 href 属性也存在类似问题
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.Comment