WEB/H5性能优化总结

咱们今天来讲说前端图形渲染优化,由于我接下来的时间可能要开始研究webgl方面的东西,因此就在这里把以前作过的H5作一个总结,现同步发布于GERRY_BLOG,TiMiGerry-知乎,转载请保留连接。

静态资源-图片

一 、图片格式
JPEG: 首先JPEG compress的整个流程是将图片的颜色rgba()进行一个转换,而后进行重采样区分高频和低频的颜色变换,从而进行一个DTA的过程,而后对高频的颜色变换采样结果进行一个压缩,接着量化和encoding,最后获得一个JPEG的压缩版。这个压缩版的图片和原始数据的图片是有差别的,虽然压缩的过程当中丢失了一些数据,可是这些差别对于人眼是没法识别的。因此在压缩以后不影响总体的浏览体验效果,同时对于页面来讲,静态资源图片的容量也能够减小不少,从而提升网页的加载速度。javascript

PNG: PNG图片的是支持透明的一种图片格式,其实质就是一个颜色的索引数据集合。它有着PNG8,PNG24,PNG32三种格式,即8位,24位,32位索引。PNG的文件格式内部有一个调色板,以PNG8 为例:PNG为256色+透明功能的格式,他的调色板中有 256 种颜色,即一个像素的颜色他须要8bit的数据长度去索引,也就是说PNG8图片的颜色只有在这256种颜色中出现,因此PNG8的颜色就没有那么的丰富,有弊也用利,它的文件大小也是PNG文件格式中最小的一种。
而PNG24的图片是须要2^24色,即一个像素的颜色他须要24bit去索引,因此png24去索引一种颜色须要的数据长度是png8的3倍,同时不支持透明,png32的图片就是在png24的基础上增长了透明的功能,PNG的图片的选取取决于图片的色彩。如果图片色彩不是很丰富且比较单一的状况下,能够考虑使用PNG8的图片,若是是图片色彩很丰富则能够选取PNG24或PNG32位的图片以减小图片资源的大小。PNG图片中每种格式图片都有一些微小的差别,实际开发中须要平衡文件大小,图片格式,图片质量和图片大小在当前项目中的重要性,,才决定使用何种图片的格式css

JPEG: 图片的压缩率比较高,适用于做为背景图片,头图的状况适用于大面积背景的状况下使用。
PNG: 格式支持透明,这种格式的图片兼容性很好,用于一些须要进行透明的背景或者弹出层,或者说在一下状况下须要追求体验质量而使用PNG图片来进行总体页面的开发。
SVG:另一种是SVG矢量图,这种格式最大的好处就是放大缩小不会失真和细腻度极高同时文件相对较小和是代码内嵌的图片格式,能有条件的话尽量使用这样的图片,固然这个也只能用于一些简单的部件例如说图标,按钮等等一写简单的业务场景。html

2、图片处理
CSS sprite:目前来说spite仍是比较经常使用的图片整理方法,他的好处是将大大小小的图片合并为一张大图,再使用图片定位来显示对应的图片,这样能够减小页面的请求,提升页面加载速度。但也有个缺点就是既然是合成一张大图,那么不少小图片就依赖这一张图片,若是这个图片没有加载出来那么整个页面基本上就缺失了,但以如今的网络来讲,基本上也能够忽略这个问题了,如今基本上是4G网络或者wifi不存在速度慢的状况。
Image-inline:使用BASE64格式嵌入到页面中也是一个很好的办法,减小htttp请求,可是实际的开发中通常也比较少这样作,由于将图片嵌入到HTML中其实到了后面也很差去维护,以个人开发经验来讲,通常是出现了没办法的状况下才使用BASE64的图片格式。
例如在开发项目中,图片资源通常都会放在不一样域的地址中,使用CANVAS生成图片的状况下,canvas.toDataUrl(…)会污染图片的原来的地址,从而致使出现了跨域的问题,后端也不可由于这张图片单独生成的时候,这个时候用BASE64就是最简单粗暴的解决方法。把图片嵌入html就解决了跨域的状况。
压缩:将图片放在一些工具上批量进行压缩。前端

HTML 页面加载渲染

1、网页渲染的过程java

图片描述

网页在加载的过程当中,首先拿到的是一个HTML文本也能够说拿到的就是一串字符串,浏览器parse解析器要将这个字符串进行一系列的词法分析,将每一个标签生成对应的一个token或者说是每一个标签对应的对象,而后从上到下解析这些token,接着就会一步步从上到下生成对应的DOM节点。
固然在词法分析的过程当中,就能够解析出link script标签,对应的web资源就会被请求加载。JavsScript会被浏览器内核的V8引擎进行执行,而css就与html相似,他会被解析成CSSOM,而后HTML,CSSM,SCRIPT,解析完毕以后结合,生成Rander Tree 拿到的这些基本信息以后,接着进入layout也就是布局,最后进行渲染Paint。web

2、 HTML的加载特色
顺序加载、并发加载:
顺序加载指的是前面提到过的词法分析,即浏览器在解析HTML页面的时候是从上往下的,依次执行。
并发加载指的是像同一个域下的静态资源是会同时的发起请求,就是并发请求,固然有并发请求那服务器也有并发请求的上限,例如谷歌浏览器一次请求统一域下的资源并发数是6。 在遇到须要大量请求图片的时候,咱们则须要使用懒加载或者预加载来进行操做。面试

图片描述

CSS阻塞、JS阻塞
css尽可能写在head中,由于css加载会阻塞页面的加载,这是有好处的,这避免了页面加载时会出现css没加载完而致使的出现页面一闪的状况,同时,css的加载是会阻塞JS的执行,但不阻塞引入JS的加载。
js尽可能写在HTML文本的底部,由于js的引入会阻塞页面的渲染,也依赖于DOM节点。因此,应该先让HTML,CSS先行加载,最后加载JS,JS的加载,固然再不影响初屏的状况下,也可使用异步加载defer,async,来加载当前不是立刻就须要的JS文件,defer的加载时基于DOM加载完毕以后,依次加载执行,而async是否是依次加载,是谁先加载完就执行谁,用这个方法须要注意JS是否依赖,JS的执行顺序也是依次执行有着相互的依赖关系,阻塞后续的JS逻辑的执行,因此得排好前后。
除了defer和acync还有就是直接使用动态加载js,通常状况下,这样的方法会在组件的状况下使用,封装一个组件而后使用js动态加载JS和CSS。数据库

Lazyload & Preload

Lazyload用于须要加载大量图片但能够根据用户的操做来决定加载数量,目的是减小对服务器的请求和减小网络流量的浪费,同时也提升了用户的体验度。例如一些电商的页面展现商品,在浏览器滚动到的地方加载相应的数据,而不是一口气把全部的数据所有列出来。在H5页面中下拉刷新,上拉加载也是很常见的作法,固然这里因为IOS自己的浏览器特性也须要作一些相应的处理。 canvas

Preload用于一些须要注重用户体验和流畅的运行页面交互的状况,在页面加载的同时先把全部的数据所有加载好以后,再打开页面。最多见的作法就是使用加载进度条,先把全部的静态资源先用一个数组存放好,而后依次加载计算百分比,到达100%以后在走下一步操做。后端

重绘与回流

咱们先说一个帧的概念,目前,大部分的设备屏幕的的刷新频率是60次/秒,也就是1000/60=1.6ms为一帧画面。 浏览器要作任何的渲染那么他的这个渲染时间必须小于1.6ms或者尽可能接近1.6ms,不然,就会出现卡顿的现象,影响用户体验。 假设如今浏览器渲染一个动画的时间恰好为一帧,那么,这一帧的画面这会首先会从新计算style(css/dom等)接着回流,更新tree,再进行重绘(painting),最后再进行图层合并(Composite)。以下图所示

图片描述

1、重绘与回流:
前端性能优化最关键的就是减小页面的重绘与回流。
回流(reflow)即当前页面的布局和几何属性发生改变时,那么就会触发回流的机制。
重绘( repaint)即render tree 的自己一些属性更新了,但不影响总体的布局,只是改变了背景,颜色等等这就叫重绘。
2、优化:
减小重绘制与回流
避免使用会触发回流的一些属性,有些属性会触发回流的机制,例如:top,height等与布局相关的属性,举个栗子:@keyframes animation中 位移的方法用translateX替代top,如下图为例:很明显就是少了一步layout,这是由于把会触发回流的top属性用translate替代,这样就使渲染的过程减小了layout这一步,使渲染的时间减小从而提升性能。

图片描述

图片描述

很明显就是少了一步layout,这是由于把会触发回流的top属性用translate替代,这样就使渲染的过程减小了layout这一步,使渲染的时间减小从而提升性能。

独立频繁渲染图层,把须要进行频繁回流重绘的那个区块,拿出来做为一个单独的图层,使浏览器的回流重绘范围减少,从而减小cpu的资源消耗。由于,浏览器渲染的过程是这样的:
现将DOM分割成多个图层;
而后将每一个层栅格化,并将节点绘制到图中;
而后图层做为纹理上传到GPU;
最后进行图层的重组,咱们只要对那个须要操做的图层独立进行重绘与回流就不会影响到其余的图层。
依照上面的渲染流程,这里就要讲到一个GPU加速的概念,既然咱们建立了一个新的合成层其实也就是开启了GPU的加速,建立新的图层方法有如下几种:
3D或透视转换
使用加速视频解码的video元素;
拥有3D(WelGL)上下文或加速器的2D上下文canvas元素;
对本身的opactiy作css运画或使用webkit转换的元素;
拥有加速css过滤的元素;
元素A拥有一个z-index比本身小的元素B,且元素B是一个合成层(换句话说就是该元素在复合层上面渲染),则元素A会提高为合成层 ;

以第2点为例:打开英雄联盟的比赛直播视频:

图片描述

咱们能够看到,这里video为何会成为一个图层,这里就有一个解释。

这里提一下第7点,由于在实际的开发项目中,尤为是移动端作一些动画效果的时候会常遇到的问题。

图片描述

依照上图的状况,元素B应该在单独的合成层上,而且屏幕的最终图像应该在 GPU 上组成。可是A元素在B元素的顶部,咱们没有指定A元素和B元素的层级。那么浏览器这个时候它将强制为元素A建立一个新的合成图层, 这样,A和B都被变成了单独的合成层。所以,使用 GPU 加速提高动画性能时,最好给当前动画元素增长一个高一点的 z-index 属性,人为干扰复合层的排序,能够有效减小 Chrome 建立没必要要的复合层,提高渲染性能。
新建图层的时候要注意:GPU 不只须要发送渲染层图像到GPU ,并且还需存储它们,以便稍后在动画中重用。不能随意的建立图层,必定要结合当前项目的状况去分析。由于建立一个新的层是有代价的,每建立一个新的渲染层,就意味着新的内存分配和更复杂的层管理。对于使用移动设备的用户来讲是一个很大的负担。

浏览器存储

1、存储介质
Cookie:cookie通常用来存放帐户验证的的信息或者一些比较敏感的用户数据,又或者是在移动端中一些项目的合做页面须要获取登陆态的信息时候,就能够用一个中转页的cookie来存放相应的数据,以便获取。总的来讲就是,用于C-S之间交互和自己数据存储。由于,他的传递方式是先从服务器生成,而后浏览器在收到服务器的返回数据中header中的set-cookie把数据写到本地,接着每次http请求(同域名下)都会夹带cookie信息,从而让服务器进行请求的用户验证

这是一个很是高效的交互机制,可是这也带来了一些问题既然每次都会带上cookie那么说明若是请求数量多就会带来流量上的消耗,会形成加载的速度慢和资源浪费,一些资源能够用cdn解决把主站和资源站的域名分开,固然这也是创建在量大的网页的状况下,若是一个网页的PV还不到10万以上那其实以今天的网络来讲这点也能够忽略不计。说到这里,这让我想起了之前去一些小公司面试的时候,当我问到他们公司web性能优化一块的时候,那些技术负责人基本上就是一句话,“流量还没到10万以上的话,能看到界面正常体验就行,怎么方便怎么来。“你们就哈哈的一笑。不过做为开发者仍是要从技术的角度出发,不管项目大小,尽量作到最好。

localStrage & sessionStrage:相对于cookie这个两个是H5新出的专门用于存储数据的属性,容量能够达到5M,惟一的区别就是一个是关闭后数据还在,另外一个是浏览器关闭后数据清空。能够做为一些临时数据的存放,例如表单或者购物车数据等。
IndexDB:这个浏览器的API,是一个浏览器数据库,在须要存储大量的结构化数据的时候才须要使用,目前使用这个API的仍是不多的,由于在客户端还不要存储特别量大的数据,数据基本是交给后台的,前端基本上须要存储的数据基本上就是临时数据和验证数据。indexDB另外一个是建立相应的离线应用。
Server Worker:这个是用于须要获取体积大和计算量很大的js文件的时候须要用到,在3D渲染的状况下,js的文件体积很大,计算量也很大,而js又是单线程的执行。这就有可能出现卡顿的状况,上一个js没处理完,下一个js就得等,SW就是独立于当前WEB,在后台能够对不一样的JS进行处理,主页面进行监听最后再进行汇总。下面是SW的生命周期:

图片描述

PWA:progressive web app指的是一种新型的app模型,经过一系列的web新特性配合UI设计达到最好的用户体验。这也是将来WEB APP的趋势。说白一点,就是会尽可能的贴近原生APP的体验度,例如他的三个主要方向,第一在没有网络的状况下也能够打开APP进行使用。其二是提升相应速度,达到最好的体验效果,另一个是生成桌面可点击应有,就是和普通的APP同样,经过点击APP进入同样有全屏和推送的功能。

浏览器缓存

一个好的缓存策略能够减小http请求和网页的延迟,减小没必要要的数据加载,下降网络负荷,从而提升页面的反应速度,能让用户有更好的浏览体验。可是,缓存只能提升第二次打开页面的反应速度,第一次打开页面仍是得由当前网络环境和设备来决定。浏览器的缓存是将文件保存在客户端,当每次会话时,浏览器都会去检查缓存的副本是否是还在有效期以内。若是是,则浏览器不会再向服务端请求文件,而是直接在内存中获取而且使用。若是文件已通过期,那么浏览器才会向服务端发起请求。这样就能减小没必要要的请求,加快页面的相应。

web缓存的信息会保存在httpheader中,经过httpheader中的一些属性去配置一些缓存策略,经过这里策略来决定资源是否须要再次向服务端发起请求加载。能够存在于responseheader中也能够存在于requestheader中,目的就是让客户端和服务端知道相互的一个缓存状况。

Cache-control是控制缓存策略的httpheader,这里面有:max-age,s-maxage, private,public,no-cache,no-store经过这些属性来进行一个缓存的配置,造成一个缓存的策略。
max-age:max-ago指的是最大的有效时间,即资源从当前请求的时间开始在这个时间范围以内,不须要向服务器发起资源请求,浏览器直接获取内存的文件使用便可,咱们打开王者荣耀的官网:

图片描述

图片描述

看到这里logo,Cache-control的max-age是86400秒,换算一下86400/3600=24,也就是这个logo在一天以内,访问这个网页都不会向服务端发起资源请求,即便服务端的这张logo发生了变化,由图片中可看到from memory cache,即从内存中获取。
s-maxage :s-maxage和max-age相似,都是在指定的时间以内不会向服务端发起资源请求,可是有一点不一样,s-maxage指向的是共享缓存(后面会进行说明),例如:cdn,而且当一个Cacha-control中同时设置了maxage和s-maxage以后,s-maxage会覆盖掉maxage和Expires 。

private 和 public: private指的是私人缓存,即只能由用户本身去访问的缓存,而public指的是共享缓存是多个浏览器均可以去访问的,若是没有指定private或者public默认为public,另外须要注意的是,s-maxage必须设置public的状况下才能够生效。
no-cache:指的是每一次都会想服务端发起请求验证缓存是否过时失效,而不是向maxage那样,在一段内就不会向服务器发起资源的请求。no-cache的用法上要注意一点,能够将maxage设置为0,而且属性设置为private:
Cache-control:private,maxage:0,no-cache

no-store指的就是禁止缓存,每次加载都须要进行资源的请求。
Expires:Expires是用来设置缓存过时时间的,他和max-age同样,都是指定都某个时间以内,只要缓存生效就不会向服务器请求资源,可是,max-age的优先级要高于expires,且须要和last-modified一块儿使用,由于,expires是强缓存,他在指定的时间以内是否是向服务端发起请求的,无论文件是否再服务器端发生了更新。还有一点Expires它相对来讲出现得比较早,因此他在浏览器兼容方面是有优点的。

Last-modified&if-last-modified:last-modified&if-last-modified指的是文件最后的修改时间,是基于客户端和服务端的缓存协商机制的 last-modified存于responseheader中 if-modifity-since存于requestheader中

图片描述

咱们看到了responseheader中有一个last-modified中有一个时间,这是时间就是服务器上这个文件的最后修改时间,浏览器会把这个时间保存下来,当下次请求的的时候,requestheader中if-modified-since就会有这个时间,告诉服务器我这个文件,最后更新的是这个时间点。若是,此时服务端的文件已经发生了改变,那么他就会从新加载,返回状态码200,若是,服务端的资源没有改变,那么浏览器端则会直接获取缓存,返回304。

Etag 和 if-none-Match:由服务器端根据文件的内容生成一个hash值,来标识资源的状态,第二次向服务端发起请求时,服务端会验证hash是否一致,来判断文件是否发生了变化,他能够解决什么问题? 仅有last-modified的状况下会如下的缺陷:
服务器文件变化了,可是内容没有变化;
服务器不能精确的获取资源的最后修改时间;
资源在秒之内进行了操做,last-modified是不能识别的;

Etag就是之内容为基准,无论有什么操做,只要内容变化,hash值必定发生变化。 另一个是,etag的优先级要比last-modified的优先级要高。再补充一点:Last-modified&ETag是在浏览器进行再一次验证的时候,才会使用到,他要先判断缓存过时的状况下(max-age),再来使用这两个东东,固然ETag的优先级是高过Last-modifity的。

缓存策略定制:
缓存策略我把它归为两大类,一是静态资源的缓存策略,而是动态资源的缓存策略,后续可能还会有新的方法,我到时再把它写出来。先注意一点,对于缓存要先分好是共享的仍是私人的,一来避免被代理缓存,二来,养成良好注意代码规范的习惯。

静态资源:静态资源指的就是css,javascript,txt,图片等固定不会修改的文件。像css,javascript这样的文件,咱们在打包的时候是会指定版本号的,也就是有一个名字都有一个后缀,一旦发生了变化,整个文件也就更新了。因此,对于静态资源来讲缓存的策略就比较简单,以当前项目的状况,作一些适当的修改便可。

动态资源: 动态资源呢,就例如股票,期货等的价格信息,这里资源是共享资源,浏览器在每次是有他们的时候浏览器或者代理服务器都会去检查是否有最新的版本,那么,咱们能够这样设:
Cache-control:public,no-cache,no-store
对于有些数据能够保存一段时间的,那就max-ago=...(秒),根据须要换算一下就能够了,例如:缓存有效一小时
Cache-control:public,max-age=86400
一个小时以后,须要严格的控制缓存,再次请求则可使用:
Cache-control:public,max-age=86400,no-cache or must-revalidate

其实也是根据需求来吧,设置无外乎多一条命令而已。

Vary:Accept-Encoding 这个是针对于那些启用了gzip压缩且被代理服务器缓存的资源,若是客户端不支持压缩,那么这种状况下可能会得不到正确的数据,这样代理服务器可能会出现两个版本的资源,一个是压缩过的,另外一个是未通过压缩的。另外一个缘由是ie浏览器,ie不支持任何带有Very头,但值不为Accept-Encoding 和 user-Agent的资源

总结:页面的优化方案须要根据当前项目的需求进行调整,达到实际体验最佳的便可。

相关文章
相关标签/搜索