性能是前端非常重要的内容,在这里学习总结常见的性能优化方式,且有机会在自己的博客中利用起来!持续更新!
原则
以下三条原则永远是一切优化的前提
- 减小代码量
- 减小请求数
- 最大化利用浏览器缓存
概览
前端性能优化方式多种多样,对于内容比较小的,在本篇中总结,如果是比较复杂的,专项解决,概览如下:
- 减少请求量
- 合并压缩打包
- CDN
- 静态 CDN 域名最好使用 2-4 个, 原因是浏览器对 max connections 有限制
- 静态类文件设置缓存
- lazyload
- 合理的使用异步请求
- 移动端响应式图片
- 雪碧图(Gulp:gulp-css-spriter webpack:optimize-css-assets-webpack-plugin)
- 代码编写
- 减少重绘。改动的 DOM 元素越深则影响越小,所以尽量深入节点改动;对某些 DOM 样式有多重变动尽量合并到一起修改。
- 避免节点深层级嵌套
- 页面 HEAD 中设置缓存
- HTML+CSS3+js 尽量用各自自特有的属性来完成效果
- 避免使用 Iframe
- 避免空链接属性
- 显式设置图片的宽高
- 渐进式增强设计:首先写一段满足所有浏览器的基本样式,再在后面针对不同高级浏览器编写更漂亮的样式
- CSS 具体应用注意点
- 使用 CSS3 编写动画效果时,开启 GPU 硬件加速提升网站动画渲染性能-webkit-transform:transition3d 和-webkit-transform:translateZ 其实是为了渲染 3D 样式,但我们设置值为 0 后,并没有真正使用 3D 效果,但浏览器却因此开启了 GPU 硬件加速模式。这种 GPU 硬件加速在当今 PC 机及移动设备上都已普及,在移动端的性能提升是相当显著
- css 减少查询层级及范围
- 避免 TAG 标签与 CLASS 或 ID 并存,如 a.top、button#submit;
- Javscript 具体应用注意点
- 尽量少用全局变量;
- 使用事件代理绑定事件
- 避免频繁操作 DOM 节点
- 不使用 eval;eval 函数效率特别低
- 减少对象查找
- 类型转换
- 对字符串进行循环操作,譬如替换、查找,应使用正则表达式;
- 避免脚本阻塞加载
- CSS 文件引入要放在头部,因为这是 HTML 渲染必备元素。
- 为了避免阻塞加载,应把脚本放到文档的末尾
- HTTP/2 对比 HTTP/1 的优势
- 头部压缩;
- 请求/响应管线化;
- 多路复用请求;
- 对请求划分优先级;
- 服务器推送流(即 Server Push 技术);
- 其他
- HTTP缓存
- DNS预解析
- Service Worker
网页图片加载优化方案
- 域名拆分(在 Chrome 浏览器,对于同一个域名,最多支持 6 个请求的并发,其他的请求将会推入到队列中等待或者停滞不前,直到六个请求之一完成后,队列中新的请求才会发出。)
- 首屏图片优先加载,等首屏图片加载完全后再去加载非首屏图片。
- 减少图片体积(在保证清晰度的前提下尽量使用体积较小的图片。而一张图片的体积由两个因素决定,该图片总的像素数目和编码单位像素所需的字节数。因此一张图片的文件大小就等于图片总像素数目乘以编码单位像素所需字节数)
- 按设备尺寸裁剪
静态资源CDN
在工作和学习中用过Bootstrap和jQuery等CDN,但是并没有了解CDN的原理,在这里详细总结。
CDN的全称Content Delivery Network,即内容分发网络。
解决问题:CDN是一个经策略性部署的整体系统,从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均而产生的用户访问网站响应速度慢的根本原因。
基本原理
- 通过在网络各处放置节点服务器,在现有的互联网基础之上新建一层智能虚拟网络,能过根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。
- 将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,解决Internet网络拥塞状况,提高用户访问网站的响应速度。
- 通过部署边缘服务器,将网站的内容发布到最接近用户的Cache服务器,使用户可以就近取得所需的内容,实现用户就近访问,有效提升网站的访问效果、安全性和稳定性。
组成部分
CDN是一种组合技术,其中包括源站、缓存服务器、智能DNS、客户端等几个重要部分。
源站
源站指发布内容的原始站点。添加、删除和更改网站的文件,都是在源站上进行的;另外缓存服务器所抓取的对象也全部来自于源站。
缓存服务器
缓存服务器是直接提供给用户访问的站点资源,有一台或数台服务器组成;当用户发起访问时,他的访问请求被智能DNS定位到离他较近的缓存服务器。如果用户所请求的内容刚好在缓存里面,则直接把内容返还给用户;如果访问所需的内容没有被缓存,则缓存服务器向邻近的缓存服务器或直接向源站抓取内容,然后再返还给用户。
智能DNS
智能DNS是整个CDN技术的核心,它主要根据用户的来源,将其访问请求指向离用户比较近的缓存服务器,如把广州电信的用户请求指向到广州电信IDC机房中的缓存服务器。通过智能DNS解析,让用户访问同服务商下的服务器,消除国内南北网络互相访问慢的问题,达到加速作用。智能DNS的出现,颠覆了传统的一个域名对应一个镜像的做法,让用户更加便捷的去访问网站。
客户端
客户端或称用户端即发起访问的普通用户,一般的访问方式是浏览器。这里就不再做详细说明。
技术组成
CDN的实现需要依赖多种网络技术的支持,其中负载均衡技术、动态内容分发与复制技术、缓存技术是比较主要的几个。
负载均衡技术
负载均衡技术不仅仅应用于CDN中,在网络的很多领域都得到了广泛的应用,如服务器的负载均衡、网络流量的负载均衡。顾名思义,网络中的负载均衡就是将网络的流量尽可能均匀分配到几个能完成相同任务的服务器或网络节点上,由此来避免部分网络节点过载。这样既可以提高网络流量,又提高了网络的整体性能。在CDN中,负载均衡又分为服务器负载均衡和服务器整体负载均衡(也有的称为服务器全局负载均衡)
。服务器负载均衡是指能够在性能不同的服务器之间进行任务分配,既能保证性能差的服务器不成为系统的瓶颈,又能保证性能高的服务器的资源得到充分利用。而服务器整体负载均衡允许Web网络托管商、门户站点和企业根据地理位置分配内容和服务。通过使用多站点内容和服务来提高容错性和可用性,防止因本地网或区域网络中断、断电或自然灾害而导致的故障。
在CDN的方案中服务器整体负载均衡发挥着重要作用,其性能高低将直接影响整个CDN的性能。
动态内容分发与复制技术
网站访问响应速度取决于许多因素,如网络的带宽是否有瓶颈、传输途中的路由是否有阻塞和延迟、网站服务器的处理能力及访问距离等。多数情况下,网站响应速度和访问者与网站服务器之间的距离有密切的关系。如果访问者和网站之间的距离过远的话,它们之间的通信一样需要经过重重的路由转发和处理,网络延误不可避免。
为了避免网络延误,就需要一个有效的方法将占网站主体的大部分静态网页、图像和流媒体数据分发复制到各地的加速节点上。
缓存技术
Web缓存服务通过几种方式来改善用户的响应时间,如代理缓存服务、透明代理缓存服务、使用重定向服务的透明代理缓存服务等。通过Web缓存服务,用户访问网页时可以将广域网的流量降至最低。对于公司内联网用户来说,这意味着将内容在本地缓存,而无须通过专用的广域网来检索网页。对于Internet用户来说,这意味着将内容存储在他们的ISP的缓存器中,而无须通过Internet来检索网页。这样无疑会提高用户的访问速度。CDN的核心作用正是提高网络的访问速度,所以,缓存技术将是CDN所采用的又一个主要技术。
各地的Cache服务器保存着源站静态内容的一份有效拷贝,网民无需直接访问源站,就可以在离自己最近的Cache服务器上获得新鲜正确的内容。目前缓存服务器可以有多种选择,比如常用的Nginx等。Cache服务器的主要工作提高内容HIT率,使得大多数的访问都能在Cache设备获得,而不用MISS回源去取.技术要点是过期机制等内容更新管理,此外Cache服务器可以将源站的一些功能分担出来,实现起来更加灵活。
雪碧图
首先什么是雪碧图呢?
雪碧图也叫CSS精灵, 是一CSS图像合成技术;
我们往往将小图标合并在一起之后的图片称作雪碧图;主要用在小图标显示上就行了。
注意:并不是所有的图片都可以用来制作雪碧图,只有描述性图片才适合。
不使用雪碧图
- 优点:调用简单、维护方便;
- 缺点:请求文件过多、引发性能问题;
使用雪碧图
- 优点:减少文件体积和请求次数,提高性能
- 缺点:调用麻烦、维护不方便;可能影响浏览器的缩放功能
等等,为什么会引发性能问题呢?
每个小图标都单独调用一图片, 即意味着每个小图标的显示都产生一个HTTP请求;一般情况下每次创建HTTP请求,请求到的内容往往是次要的(除非文件特别大), 性能开销主要在请求、以及响应阶段;造成的性能消耗肯定不小!
生成雪碧图
生成雪碧图的方式大致有如下:
- CSS Gaga
- photoShop
- gulp
- webpack 对于程序员而言,推荐使用后两种方式!具体可参考资料!有时间自己实践且记录!
DNS预解析
DNS与域名解析
DNS全称为Domain Name System,即域名系统,是域名和IP地址相互映射的一个分布式数据库。域名解析即通过主机名,最终得到该主机名对应的IP地址的过程。
DNS解析时间可能导致大量用户感知延迟,DNS解析所需的时间差异非常大,延迟范围可以从1ms(本地缓存结果)到普遍的几秒钟时间。所以利用DNS预解析是有意义的。
DNS预解析是浏览器试图在用户访问链接之前解析域名,这是计算机的正常DNS解析机制。域名解析后,如果用户确实访问该域名,那么DNS解析时间将不会有延迟。
DNS预解析在某个页面中包含非常多的链接时非常有效,如搜索结果页或包含大量图片的首页(如电商,有专门的图片服务器)。
遇到网页中的超链接,DNS prefetching从中提取域名并将其解析为IP地址,这些工作在用户浏览网页时,使用最少的CPU和网络在后台进行解析。
DNS Prefetching简介
DNS Prefetch是一种DNS预解析技术,当你浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在你单击当前网页中的连接时就无需进行DNS的解析,减少用户等待时间,提高用户体验。
我们DNS解析的时候,需要用域名去DNS解析匹配IP,这个是需要时间的,如果加了dns-perfetch呢,浏览器会记住(缓存)这个解析,直接就请求过去了,不需要再走DNS解析。就是这么简单。
DNS请求需要的带宽非常小,但是延迟却有点高,这点在手机网络上特别明显。DNS预解析能让延迟明显减少一些,例如用户点击链接时。在某些情况下,延迟能减少一秒钟。
在某些浏览器中这个预读取的行为将会与页面实际内容并行发生(而不是串行)。正因如此,某些高延迟的域名的解析过程才不会卡住资源的加载。
这样可以极大的加速(尤其是移动网络环境下)页面的加载。在某些图片较多的页面中,在发起图片加载请求之前预先把域名解析好将会有至少 5% 的图片加载速度提升。
普遍来说合理的dns prefetching能对页面性能带来50ms ~ 300ms的提升。
使用方式
X-DNS-Prefetch-Control 头控制着浏览器的DNS预解析功能
- X-DNS_prefetch-Control: on|off
- on:启用DNS预解析。
- off:关闭DNS预解析。
强制查询特定主机名
//开始是为了适配https和http。就是当前请求链接是https,那么这个//前面自动补充https,反则补充http
<link rel="dns-prefetch" href="//cdn.sojson.com">
使用优化
手动 dns prefetching 的代码实际上还是会增加html的代码量的,特别是域名多的情况下。所以,最优的方案应该是:通过js初始化一个iframe异步加载一个页面,而这个页面里包含本站所有的需要手动dns prefetching的域名。
示例
打开和关闭DNS预读取
你可以通过在服务器端发送 X-DNS-Prefetch-Control 报头,或是在文档中使用值为 http-equiv 的标签:
<meta http-equiv="x-dns-prefetch-control" content="off">
特定域名
你可以通过使用 rel 属性值为 link type 中的 dns-prefetch 的 标签来对特定域名进行预读取:
<link rel="dns-prefetch" href="http://www.test.com/">
特性
- Chrome会记住最近使用的10个domain,并且在开启浏览器时自动解析,因此在打开这些常用页面的时候,并不会有DNS Lookup的延迟情况。
- chrome使用8个线程专门做DNS Prefetching,而且chrome本身不做dns记录的cache,是直接从操作系统读dns。所以直接修改系统的dns记录或者host是可以直接影响chrome。
- 浏览器会对a标签的href自动启用DNS Prefetching,所以a标签里包含的域名不需要在head中手动设置link。但是在HTTPS下面不起作用,需要meta来强制开启功能。这个限制的原因是防止窃听者根据DNS Prefetching推断显示在HTTPS页面中超链接的主机名。
- DNS解析的包很小,一个UDP的包小于100 bytes,却平均可节省200ms。
- 本地缓存DNS数量有限,可暂存50-200个domain,Chrome会决定该删除哪些domain的缓存,常用的网站会被标记为“最近使用”,不会那么快被删除。而如google.com、yahoo.com等大型网站过期时间大概在5分钟左右,可以更好的适应服务变化。
具体场景
页面中的静态资源在不同的domain下,如CSS、JS、图片等文件,适合在以下场景中使用:
- 电商网站的商品页大量载入不同domain下的商品图,如淘宝
- 手机网页
- 大型网站
- js或服务端重定向
解析过程
下面通过示意图学习解析的具体过程:
发展
现在浏览器也认识到DNS预解析对性能的提高,chrome浏览器就支持自动预解析。
- chrome 会自动把当前页面的所有带href的link的dns都prefetch一遍
- 需要手动添加link标签的场景是:你预计用户在后面的访问中需要用到当前页面的所有链接都不包含的域名
正确的使用姿势
- 对静态资源域名做手动dns prefetching。
- 对js里会发起的跳转、请求做手动dns prefetching。
- 不用对超链接做手动dns prefetching,因为chrome会自动做dns prefetching。
- 对重定向跳转的新域名做手动dns prefetching,比如:页面上有个A域名的链接,但访问A会重定向到B域名的链接,这么在当前页对B域名做手动dns prefetching是有意义的。
使用情况
打开京东和淘宝,都会发现大量的dns-prefetch
标签,看了这你还会担心毫无用处吗?