乐趣区

前端性能优化常用总结

正文
前端优化层出不穷,移动端大行其道的现在,我们可以说优化好移动端,PC 端也将会更好。所以,我们可以综合以下图片进行一些分析,如图:

图中已经对前端性能做了一些概括。但其实,我觉得我们可以将这个概括更加精准,扼要,丰富。所以,接下来我会从三个方面就前端性能进行总结:网络方面、DOM 操作及渲染方面、数据方面。
网络方面 web 应用,总是会有一部分的时间浪费在网络连接和资源下载方面。往往建立一次网络连接是需要时间成本的。而且浏览器同一时间所发送的网络请求数是有限的。所以,这个层面的优化可以从「减少请求数目」开始:
减少 http 请求:在 YUI35 规则中也有提到,主要是优化 js、css 和图片资源三个方面,因为 html 是没有办法避免的。因此,我们可以做一下的几项操作:
合并 js 文件合并 css 文件雪碧图的使用 (css sprite) 使用 base64 表示简单的图片
上述四个方法,前面两者我们可以使用 webpack 之类的打包工具进行打包;雪碧图的话,也有专门的制作工具;图片的编码是使用 base64 的,所以,对于一些简单的图片,例如空白图等,可以使用 base64 直接写入 html 中。
回到之前网络层面的问题,除了减少请求数量来加快网络加载速度,往往整个资源的体积也是,平时我们会关注的方面。
减小资源体积:可以通过以下几个方面进行实施:
gzip 压缩 js 混淆 css 压缩图片压缩
gzip 压缩主要是针对 html 文件来说的,它可以将 html 中重复的部分进行一个打包,多次复用的过程。js 的混淆可以有简单的压缩(将空白字符删除)、丑化(丑化的方法,就是将一些变量缩小)、或者可以使用 php 对 js 进行混淆加密。css 压缩,就是进行简单的压缩。图片的压缩,主要也是减小体积,在不影响观感的前提下,尽量压缩图片,使用 png 等图片格式,减少矢量图、高清图等的使用。这样子的做法不仅可以加快网页显示,也能减少流量的损耗。
除了以上两部分的操作之外,在网络层面我们还需要做好缓存工作。真正的性能优化来说,缓存是效率最高的一种,往往缩短的加载时间也是最大的。
缓存:可以通过以下几个方面来描述:
DNS 缓存 CDN 部署与缓存 http 缓存
由于浏览器会在 DNS 解析步骤中消耗一定的时间,所以,对于一些高访问量网站来说,做好 DNS 的缓存工作,就会一定程度上提升网站效率。CDN 缓存,CDN 作为静态资源文件的分发网络,本身就已经提升了,网站静态资源的获取速度,加快网站的加载速度,同时也给静态资源做好缓存工作,有效的利用已缓存的静态资源,加快获取速度。http 缓存,也是给资源设定缓存时间,防止在有效的缓存时间内对资源进行重复的下载,从而提升整体网页的加载速度。
其实,网络层面的优化还有很多,特别是针对于移动端页面来说。众所周知,移动端对于网络的敏感度更加的高,除了目前的 4G 和 WIFI 之外,其他的移动端网络相当于弱网环境,在这种环境下,资源的缓存利用是相当重要的。而且,减少 http 的请求次数,也是至关重要的,移动端弱网环境下,对于 http 请求的时间也会增加。所以,我们可以看一下我们在移动端网络方面可以做的优化:
移动端优化:使用以下几种方式来加快移动端网络方面的优化:
使用长 cache,减少重定向首屏优化,保证首屏加载数据小于 14kb 不滥用 web 字体
「使用长 cache」,可以使得移动端的部分资源设定长期缓存,这样可以保证资源不用向服务器发送请求,来比较资源是否更新,从而避免 304 的情况。304 重定向,在 PC 端或许并不会影响网页的加载速度,但是,在移动端网络不稳定的前提下,多一次请求,就多了一部分加载时间。「首屏优化」,对于移动端来说是至关重要的。2s 时间是用户的最佳体验,一旦超出这个时间,将会导致用户的流失。所以,针对移动端的网络情况,不可能在这么短时间内加载完成所有的网页资源,所以我们必须保证首屏中的内容被优先显示出来,而且基于 TCP 的慢启动和拥塞控制,第一个 14kb 的数据是非常重要的,所以需要保证首部加载数据能够小于 14kb。「不滥用 web 字体」,web 字体的好处就是,可以代替某些图片资源,但是,在移动端过多的 web 字体的使用,会导致页面资源加载的繁重,所以,慎用 web 字体
渲染和 DOM 操作方面首先,简单的聊一下优化渲染的重要性。在网页初步加载时,获取到 HTML 文件之后,最初的工作是构建 DOM 和构建 CSSOM 两个树,之后将他们合并形成渲染树,最后对其进行打印。我们可以通过图片来看一下,简单的过程:

这里整个过程拉出来写,具体可以再写一篇文章,恕我偷下懒,推荐一篇比较好的文章给大家吧。浏览器渲染过程与性能优化继续我们的话题,我们可以如何去缩短这个过程呢?可以从以下几个操作进行优化。
优化网页渲染:
css 的文件放在头部,js 文件放在尾部或者异步尽量避免內联样式
css 文件放在「头部加载」,可以保证解析 DOM 的同时,解析 css 文件。因为,CSS(外链或内联)会阻塞整个 DOM 的渲染,然而 DOM 解析会正常进行,所以将 css 文件放在头部进行解析,可以加快网页的构建速度。假设将其放在尾部,那时 DOM 树几乎构建,这时就得等到 CSSOM 树构建完成,才能够继续下面的步骤。「js 放在尾部」:js 文件不同,将 js 文件放在尾部或者异步加载的原因是 JS(外链或内联)会阻塞后续 DOM 的解析,后续 DOM 的渲染也将被阻塞,而且一旦 js 中遇到 DOM 元素的操作,很可能会影响。这方面可以推荐一篇文章——异步脚本载入提高页面性能。「避免使用内联样式」,可以有效的减少 html 的体积,一般考虑内联样式的时候,往往是样式本身体积比较小,往往加载网络资源的时间会大于它的时候。
除了页面渲染层面的优化,当然最重要的就是 DOM 操作方面的优化,这部分的优化应该是最多的,而且也是平时开发可以注意的地方。如果开发前期明白这些原理,同时付诸实践的话,就可以在后期的性能完善上面少下很多功夫。那么,接下来我们可以来看一下具体的操作:
DOM 操作优化:
避免在 document 上直接进行频繁的 DOM 操作使用 classname 代替大量的内联样式修改对于复杂的 UI 元素,设置 position 为 absolute 或 fixed 尽量使用 css 动画使用 requestAnimationFrame 代替 setInterval 操作适当使用 canvas 尽量减少 css 表达式的使用使用事件代理
前面三个操作,其实都是希望『减少回流和重绘』。其实,进行一次 DOM 操作的代价是非常之大的,以前可以通过网页操作是否卡顿来进行判断,但是,现代浏览器的进步已经大大减少了这方面的影响。但是,我们还是需要清楚,如何去减少回流和重绘的问题。因为这里不想细说这方面的知识,想要了解的话,可以看这篇文章——回流与重绘:CSS 性能让 JavaScript 变慢?。这可是张鑫旭大大的一篇文章呦(^.^)。「尽量使用 css 动画」,是因为本身 css 动画比较简单,而且相较于 js 的复杂动画,浏览器本身对其进行了优化,使用上面不会出现卡顿等问题。「使用 requestAnimationFrame 代替 setInterval 操作」,相信大家都有所耳闻,setInterval 定时器会有一定的延时,对于变动性高的动画来说,会出现卡顿现象。而 requestAnimationFrame 正好解决的整个问题。「适当使用 canvas」,不得不说 canvas 是前端的一个进步,出现了它之后,前端界面的复杂性也随之提升了。一些难以完成的动画,都可以使用 canvas 进行辅助完成。但是,canvas 使用频繁的话,会加重浏览器渲染的压力,同时导致性能的下降。所以,适当时候使用 canvas 是一个不错的建议。「尽量减少 css 表达式的使用」,这个在 YUI 规则中也被提到过,往往 css 的表达式在设计之初都是美好的,但在使用过程中,由于其频繁触发的特性,会拖累网页的性能,出现卡顿。因此在使用过程中尽量减少 css 表达式的使用,可以改换成 js 进行操作。「使用事件代理」:往往对于具备冒泡性质的事件来说,使用事件代理不失为一种好的方法。举个例子:一段列表都需要设定点击事件,这时如果你给列表中的每一项设定监听,往往会导致整体的性能下降,但是如果你给整个列表设置一个事件,然后通过点击定位目标来触发相应的操作,往往性能就会得到改善。
DOM 操作的优化,还有很多,当然也包括移动端的。这个会在之后移动端优化部分被提及,此处先卖个关子。上面我们概述了开始渲染的时候和 DOM 操作的时候的一些注意事项。接下来要讲的是一些小细节的注意,这些细节可能对于页面影响不大,但是一旦堆积多了,性能也会有所影响。
操作细节注意:
避免图片或者 frame 使用空 src 在 css 属性为 0 时,去掉单位禁止图像缩放正确的 css 前缀的使用移除空的 css 规则对于 css 中可继承的属性,如 font-size,尽量使用继承,少一点设置缩短 css 选择器,多使用伪元素等帮助定位
上述的一些操作细节,是平时在开发中被要求的,更可以理解为开发规范。(基本操作,坐下 ^_^)
列举完基本操作之后,我们再来聊一下移动端在 DOM 操作方面的一些优化。
移动端优化:
长列表滚动优化函数防抖和函数节流使用 touchstart、touchend 代替 clickHTML 的 viewport 设置开启 GPU 渲染加速
首先,长列表滚动问题,是移动端需要面对的,IOS 尽量使用局部滚动,android 尽量使用全局滚动。同时,需要给 body 添加上 -webkit-overflow-scrolling: touch 来优化移动段的滚动。如果有兴趣的同学,可以去了解一下 ios 和 android 滚动操作上的区别以及优化。「防抖和节流」,设计到滚动等会被频繁触发的 DOM 事件,需要做好防抖和节流的工作。它们都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
介绍:函数防抖,当调用动作过 n 毫秒后,才会执行该动作,若在这 n 毫秒内又调用此动作则将重新计算执行时间;函数节流,预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
「touchstart、touchend 代替 click」,也是移动端比较常用的操作。click 在移动端会有 300ms 延时,这应该是一个常识呗。(不知道的小伙伴该收藏一下呦)。这种方法会影响用户的体验。所以做优化时,最简单的方法就是使用 touchstart 或者 touchend 代替 click。因为它们事件执行顺序是 touchstart->touchmove->touchend->click。或者,使用 fastclick 或者 zepto 的 tap 事件代替 click 事件。「HTML 的 viewport 设置」,可以防止页面的缩放,来优化性能。「开启 GPU 渲染加速」,小伙伴们一定听过 CPU 吧,但是这里的 GPU 不能和 CPU 混为一谈呦。GPU 的全名是 Graphics Processing Unit,是一种硬件加速方式。一般的 css 渲染,浏览器的渲染引擎都不会使用到它。但是,在 3D 渲染时,计算量较大,繁重,浏览器会开启显卡的硬件加速来帮助完成这些操作。所以,我们这里可以使用 css 中的 translateZ 设定,来欺骗浏览器,让其帮忙开启 GPU 加速,加快渲染进程。
DOM 部分的优化,更多的是习惯。需要自己强制要求自己在开发过程中去注意这些规范。所以,这部分的内容可以多关注一下,才能够慢慢了解。同时,本人对于上述几点的描述是概括性的。并没有对其进行详细的展开。因此,也要求你去细细的查阅 Google 呦。数据方面数据,也可以说是前端优化方面比较重要的一块内容。页面与用户的交互响应,往往伴随着数据交互,处理,以及 ajax 的异步请求等内容。所以,我们也可以来聊聊这一块的知识。首先是对于图片数据的处理:
图片加载处理:
图片预加载图片懒加载首屏加载时进度条的显示
「图片预加载」,预加载的寓意就是提前加载内容。而图片的预加载往往会被用在图片资源比较大,即时加载时会导致很长的等待过程时,才会被使用的。常见场景:图片漫画展示时。往往会预加载一张到两张的图片。「图片懒加载」,懒加载或许你是第一次听说,但是,这种方式在开发中会被经常使用。首先,我们需要明白一个道理:往往只有看到的资源是必须的,其他资源是可以随着用户的滚动,随即显示的。所以,特别是对于图片资源特别多的网站来说,做好图片的懒加载是可以大大提升网页的载入速度的。
常见的图片懒加载的方式就是:在最初给图片的 src 设置一个比较简单的图片,然后将图片的真实地址设置给自定义的属性,做一个占位,然后给图片设置监听事件,一旦图片到达视口范围,从图片的自定义属性中获取出真是地址,然后赋值给 src,让其进行加载。
「首屏进度条的显示」:往往对于首屏优化后的数据量并不满意的话,同时也不能进一步缩短首屏包的长度了,就可以使用进度条的方式,来提醒用户进行等待。
讲完了图片这一块数据资源的处理,往往我们需要去优化一下异步请求这一部分的内容。因为,异步的数据获取也是前端不可分割的。这一部分我们也可以做一定的处理:
异步请求的优化:
使用正常的 json 数据格式进行交互部分常用数据的缓存数据埋点和统计
「JSON 交互」,JSON 的数据格式轻巧,结构简单,往往可以大大优化前后端的数据通信。「常用数据的缓存」,可以将一些用户的基本信息等常用的信息做一个缓存,这样可以保证 ajax 请求的减少。同时,HTML5 新增的 storage 的内容,也不用怕 cookie 暴露,引起的信息泄漏问题。「数据埋点和统计」,对于资深的程序员来说,比较了解。而且目前的大部分公司也会做这方面的处理。有心的小伙伴可以自行查阅。
最后,还有就是大量数据的运算。对于 javascript 语言来说,本身的单线程就限制了它并不能计算大量的数据,往往会造成页面的卡顿。而可能业务中有些复杂的 UI 需要去运行大量的运算,所以,webWorker 的使用是至关重要的。或许,前端标准普及的落后,会导致大家对于这些新生事物的短暂缺失吧。总结本篇文章就前端性能这个话题做了一个总结。或许,并不全面,但是都是一些平时开发中会被经常用到的知识。希望有心者能够去亲身的尝试一下这些方面的优化。本篇的概述了一下几个知识点:
网络层面的优化数据层面的优化 DOM 操作与渲染层面的优化
原文链接:https://juejin.im/post/59e1bb…

退出移动版