【性能优化】前端性能优化方案都帮你整理好了(全面系统)!

前言

前端是庞大的,包括 HTML、 CSS、 Javascript、Image 、Flash等等各种各样的资源。前端优化是复杂的,针对方方面面的资源都有不同的方式。那么,前端优化的目的是什么 ?

1. 从客户端角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。
2. 从服务器端角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。
  
总之,恰当的优化不仅能够改善站点的用户体验并且能够节省相当的资源利用。

前端优化的途径有很多,这里我整理成三个大点,第一个是HTTP请求层面,第二个是程序代码层面,第三个就是请求源就近响应源层面

一、HTTP请求层面

这条策略基本上所有前端人都知道,而且也是最重要最有效的。都说要减少 HTTP请求,那请求多了到底会怎么样呢 ?首先,每个请求都是有成本的,既包含时间成本也包含资源成本。一个完整的请求都需要经过 DNS域名解析、与服务器建立连接(建立tcp通道,三次握手)、发送数据、等待服务器响应、接收数据这样一个 “漫长” 而复杂的过程、最后浏览器还需要解析html,css生成对应Render DOM渲染树,经过一系列回流重绘以及js执行生成相应的页面给用户。

那么减少 HTTP请求数的主要途径包括:

1. 减少 HTTP请求数(量化)
(1) 优化图片请求数:说到请求数,那页面中图片的请求肯定脱不了干系的,一个图片就会发送一次请求,所以对于图片的请求量,我们可以使用CSS Sprites将图片整合到一张大图,然后通过background-position拿到对应的图片进行使用,对于请求数来说,这无疑将好几个图片请求,变成了一个请求,当然这也同样增加了请求所占带宽,所以也算是美中有一点点不足吧;其次也就是图片base64化,base64编码的图片是不需要消耗请求数的,但要注意使用base64的图片尽可能不要超过10k,因为图片的大小越大,转化成的base64码也就越多,大大影响代码质量;最后一个也就是的 字体图标,这种图标是一种字体格式的Iconfont,这种图标也是不消耗请求的,而且一般都可以满足我们现阶段项目中大多数小ICON → 阿里巴巴图标库

(2) 资源合并与压缩:如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image 都可以用相应的工具进行压缩,压缩后往往能省下不少空间

(3) 图片懒加载(Lazy Load Images):想必大家也知道,像淘宝,花瓣这种图片特别多的网站难道都是将当前页面的图片都给用户加载吗?显然不可能,对于这种图片多的页面都是进行懒加载处理来减少首屏中对图片的请求数,但是注意这里的减少 HTTP请求数,并不是说通过懒加载可以让加载的图片不需要发送请求,而是当你进入页面时,通过懒加载的机制会先给你加载部分图片,而并不是当前页面的图片都需要发送请求;只有当用户继续往后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。简单说一下实现原理,也就是前端拿到后端响应数据图片时,将图片的地址,先放在img便签上的 data-src 属性上,此时 src 这个属性为空,然后配合JS监听用户的页面滚动距离,只要当前图片进入这个窗口可视区域就将 data-src 里的图片地址放在 src上实现图片的显示

(4) 合理设置 HTTP缓存:缓存的力量是强大的,恰当的缓存设置可以大大的减少 HTTP请求。以首页为例,当浏览器没有缓存的时候假设访问一共会发出 50个请求,共 500多 K数据 ,而当第二次访问即浏览器已缓存之后访问则仅有 10个请求,共 20多 K数据。 (这里需要说明的是,如果直接 F5刷新页面的话效果是不一样的,这种情况下请求数还是一样,不过被缓存资源的请求服务器是 304响应,只是 Header没有Body ,可以节省带宽 )
怎样才算合理设置?例如很少变化的图片资源可以直接通过 HTTP Header中的Expires设置一个很长的过期头 ;变化不频繁而又可能会变的资源可以使用 Last-Modifed来做请求验证。尽可能的让资源能够在缓存中待得更久。虽然这一点大部分是后端设置,这个就要涉及到后端对响应的标志,合理设置可以减少前后端过多的交互,加快页面加载速度

2. 减少 HTTP请求所占宽带(质化)
(1) 资源合并与压缩(这个前面量化已经提及过,这里还是再写一下吧,可以理解为合并减少了请求量,压缩就减少了请求所占宽带):如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image 都可以用相应的工具进行压缩,压缩后往往能省下不少空间

(2) 避免大图片(体积大)请求:大图片的请求慢是必然的,也会影响用户的体验,但是项目中肯定避免不了有几个大图片的加载,那么我们就可以对图片体积进行适当的压缩,注意不能影响图片的质量比如失真模糊,这种一般UI设计师都会对这些图片进行处理的;当然如果公司没有分工那么明确的话,可能前端就要完成这份工作了(所以要会做,现在都是有软件可以完成的),但是如果你不知道怎么处理或者你压缩的时候还是出现了质量问题,建议使用SVG格式的图片,这种图片不但体积相对于其他格式的图片小,最重要的是放大不失真!


二、程序代码层面

代码层面的优化,是程序员的必备素质,代码的规范不仅仅是维护上的提升,也是性能的提升(高质量的代码影响性能你不能不信!),不多哔哔赖赖我们看看有哪些方法:

1. 样式及脚本代码位置
(1) 将 CSS放在 HEAD中而JS脚本置底:这个大家应该都是知道的,这里说一下原因 → ① 如果将 CSS放在其他地方比如 BODY中,则浏览器有可能还未下载和解析到 CSS就已经开始渲染页面了,这就导致页面由无 CSS状态跳转到 CSS状态,用户体验比较糟糕。除此之外,有些浏览器会在 CSS下载完成后才开始渲染页面,如果 CSS放在靠下的位置则会导致浏览器将渲染时间推迟;② 在HTTP1.1后浏览器对HTTP请求是可以并发进行的,这一特点使得其能够更快的加载资源,然而JS脚本在加载时却会阻塞其他资源,例如在脚本加载完成之前,它后面的图片、样式以及其他脚本都处于阻塞状态,直到脚本加载完成后才会开始加载。如果将脚本放在比较靠前的位置,则会影响整个页面的加载速度从而影响用户体验。解决这一问题的方法有很多,而最简单可依赖的方法就是将脚本尽可能的往后挪,减少对并发下载的影响。

2. HTML
(1) 合理利用HTML5语义化便签,并且标签不乱嵌套,减少无用便签;你们应该会问这跟前端性能优化有什么关系? 注意了DOM结构的合理设计,会减少浏览器在解析HTML DOM树时的速度(DOM结构如果越复杂,遍历时就会损耗跟多更多性能),具体可以看这篇文章 → 重绘与回流

(2) 自从HTML5新增的一个重要的网页存储的API特性Web Storage,方便Web应用的离线使用。除此之外,新的API相对于cookie也有着高安全性,高效率,更大空间等优点。正因为每次请求都会携带cookie所以当中还是会消耗对应的请求数,而session Storage和local Storage正好可以优化这一点;

3.CSS
(1) 在大多数人的观念中,都觉得浏览器对 CSS选择符的解析式从左往右进行的,例如 #pic A { color: #444; } 这样一个选择符,如果是从左往右解析则效率会很高,因为第一个 ID选择基本上就把查找的范围限定了,但实际上浏览器对选择符的解析是从右往左进行的。如上面的选择符,浏览器必须遍历查找每一个 A标签的祖先节点,效率并不像之前想象的那样高;所以既然浏览器是这样解析CSS的话,我们是不是应该在写CSS样式的时候不要有深层次的嵌套,这个性能优化,跟上面提到的HTML一样,也是在浏览器解析CSS DOM树的时候涉及的,只要写的嵌套太深入(无论是HTML还是CSS结构)都是会让浏览器解析速度变慢;

(2) 在动画方面,应该让动画本身脱离文档流,这样可以减少页面中不断的重绘回流,因为动画本身是运动的,如果存在文档流中,会影响旁边的布局,浏览器就会重新计算这部分涉及的元素大小及位置等 ;其次就是使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 → 关于这些都可以看这篇文章 重绘与回流 里面说的很清楚

4.Javascript
(1) 减少DOM节点的操作:
DOM操作应该是脚本中最耗性能的一类操作,例如增加、修改、删除 DOM元素或者对 DOM集合进行操作。如果脚本中包含了大量的 DOM操作则需要注意以下几点:

a. HTML Collection(HTML收集器,返回的是一个数组内容信息)
  在脚本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection类型的集合,在平时使用的时候大多将它作为数组来使用,因为它有 length属性,也可以使用索引访问每一个元素。不过在访问性能上则比数组要差很多,原因是这个集合并不是一个静态的结果,它表示的仅仅是一个特定的查询,每次访问该集合时都会重新执行这个查询从而更新查询结果。所谓的 “访问集合” 包括读取集合的 length属性、访问集合中的元素。
  因此,当你需要遍历 HTML Collection的时候,尽量将它转为数组后再访问,以提高性能。即使不转换为数组,也请尽可能少的访问它,例如在遍历的时候可以将 length属性、成员保存到局部变量后再使用局部变量。
  
b. Reflow & Repaint
除了上面一点之外, DOM操作还需要考虑浏览器的 Reflow和Repaint ,因为这些都是需要消耗资源的

c. 现阶段的框架如Vue/React操作的都是虚拟DOM,框架底层通过DIff算法对比前后DOM的不同进行操作,具体不在这细讲了

(2) 变量数据访问:
  Javascript中的数据访问包括直接量 (字符串、正则表达式 )、变量、对象属性以及数组,其中对直接量和局部变量的访问是最快的,对对象属性以及数组的访问需要更大的开销。当出现以下情况时,建议将数据放入局部变量:
  a. 对任何对象属性的访问超过 1次
  b. 对任何数组成员的访问次数超过 1次
另外,还应当尽可能的减少对对象以及数组深度查找。

(3) 减少作用域链查找(这方面设计到一些内容的相关问题):
  前文谈到了作用域链查找问题,这一点在循环中是尤其需要注意的问题。如果在循环中需要访问非本作用域下的变量时请在遍历之前用局部变量缓存该变量,并在遍历结束后再重写那个变量,这一点对全局变量尤其重要,因为全局变量处于作用域链的最顶端,访问时的查找次数是最多的;我们来对比一下两种写法 ↓
① 低效率的写法:

// 全局变量 
var globalVar = 1; 
function myCallback(info){ 
for( var i = 100000; i--;){ 
//每次访问 globalVar 都需要查找到作用域链最顶端,本例中需要访问 100000 次 
globalVar += i; 
}
} 

② 更高效的写法:

// 全局变量 
var globalVar = 1; 
function myCallback(info){ 
// 局部变量缓存全局变量 
var localVar = globalVar; 
for( var i = 100000; i--;){ 
// 访问局部变量是最快的 
localVar += i; 
} 
// 本例中只需要访问 2次全局变量
// 在函数中只需要将 globalVar中内容的值赋给localVar
globalVar = localVar; 
}

此外,要减少作用域链查找还应该减少闭包的使用。

(4) 字符串拼接
在 Javascript中使用"+" 号来拼接字符串效率是比较低的,因为每次运行都会开辟新的内存并生成新的字符串变量,然后将拼接结果赋值给新变量。与之相比更为高效的做法是使用数组的 join方法,即将需要拼接的字符串放在数组中最后调用其 join方法得到结果。不过由于使用数组也有一定的开销,因此当需要拼接的字符串较多的时候可以考虑用此方法;其次就是ES6的模版语法完美KO了这种通过"+"进行拼接的做法,方便高效

(5) Lazy Load Javascript(这里可以理解为按需加载,如Vue中的异步加载语法,结合webpack进行代码分割)
  随着 Javascript框架的流行,越来越多的站点也使用起了框架。不过,一个框架往往包括了很多的功能实现,这些功能并不是每一个页面都需要的,如果下载了不需要的脚本则算得上是一种资源浪费 -既浪费了带宽又浪费了执行花费的时间。目前的做法大概有两种,一种是为那些流量特别大的页面专门定制一个专用的 mini版框架,另一种则是 Lazy Load。YUI 则使用了第二种方式,在 YUI的实现中,最初只加载核心模块,其他模块可以等到需要使用的时候才加载。而Vue中就是在路由配置中进行异步加载的语法,在SPA单页面应用是很常见的

(6) 提高代码的利用率:
a. 何为代码利用率(代码覆盖率)?
我就通俗说一下,具体可以自行Goole。代码覆盖率就是指当前页面加载的文件有多少被真正的激活使用(图中绿色为激活的代码,红色就是待激活的代码)
在这里插入图片描述

b. 怎么看?
在这里插入图片描述

上图为爱奇艺首页加载时,通过使用 Show Coverage 测试出来的,通过红框中可以看出来,爱奇艺首屏加载完成后有70%的代码覆盖率,很nb了,有55以上都挺不错的了;

c. 怎么优化,怎么做?
其一 → 当前加载的页面不掺杂其他页面不相关的代码,并且避免因为疏忽或页面由多个模块拼接而成,然后每个模块中请求了同样的资源时,会导致资源的重复请求;

其二 → 异步代码,关于与用户交互的逻辑,使用异步代码进行处理,可以增加代码利用率,通过coverage可以进行测试,当我们成功触发交互,对应的异步代码就会变绿,并且异步的代码是可以提升覆盖率的,最后说一句现在前端的优化不能在只单单考虑缓存这个层面,也要关注代码利用率层面;

其三 → 最近不是Vue3.0重磅出炉吗?有了解过的小伙伴应该知道Vue3.0优化了"摇树 Tree-shaking"的功能,这个功能可厉害了,他可以自动识别页面中并未使用的代码进行Shaking,当然不是说因为这个让大伙觉得是不是要升级Vue了不然跟不上潮流,毕竟刚出炉的香芋烫手的很,需要时间;这个如果不使用Vue3.0进行开发的话,还可以通过去配置Webpack来实现 Tree-shaking的功能 这个完全可以参考 → webpack官方文档


三、请求源就近响应源层面

这个名字我是乱起的,所以不用在意。只要知道接下来指的是什么就行;

(1) CDN加速:这种服务一般都是有专门的供应商提供,只需要钱到位就行;主要就是实现,请求源(就比如用户在广州请求了项目数据,CDN就会解析这个ip拿到请求的地址)发送请求后,响应源(根据购买的CDN部署地进行快速分配距离这个ip地址最近的服务器进行请求的接收,最后返回对应的相应数据给客户端)返回响应数据;

结语

本文从三个方面阐述了前端优化的各种方式做了一个总结,这些方法基本上都是前端开发人员在开发的过程中可以借鉴和实践的,希望可以帮到你;当然优化的方法可能还有,只是我没有提及或者压根还不知道,所以承蒙各路大佬指点迷津,一起加油~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Umbrella_Um/article/details/102546329

发布了134 篇原创文章 · 获赞 80 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Umbrella_Um/article/details/102546329