webpack性能优化

1.不要让loader做太多事情

2.处理第三方库

3.构建结果体积压缩

  a.文件可视化,找出导致体积过大的原因

  b.拆分资源

  c.删除冗余代码

  d.按需加载

4.webpack Gzip压缩

图片优化

总的来说就是根据图片类型的特点去使用图片

1.jpg图片

特点是有损压缩、高质量压缩、体积小、加载快、不支持透明,适用于呈现色彩丰富的图片,适合用作背景图、轮播图或Banner图的格式

2.png图片

特点是无损压缩、高质量压缩、体积大、支持透明,适用于呈现小的Logo,或者颜色简单且对比强烈的图片或背景图的格式

3.SVG图片

特点是体积小,不失真,兼容性好,可压缩性强,可编程,渲染成本高,学习成本高,最适合带有大型渲染区域的应用程序(地图应用)

4.雪碧图

将一个页面涉及到的所有图片都包含到一张大图中去,然后利用CSS的 background-image,background-
repeat,background-position 的组合进行背景定位。利用CSS
Sprites能很好地减少网页的http请求,从而大大的提高页面的性能;CSS Sprites能减少图片的字节。

5.Base64


对图片进行Base64编码,会得到一串字符串,浏览器会直接将这串字符串解码为图片,这样就不用发送http请求了,但是这样的缺点是图片会膨胀,体积会增加,所以它的应用条件是:图片尺寸小、无法用雪碧图、图片更新频率低(不需要我们重复编码和修改文件内容,维护成本较低)

6.webP

集各种格式的优点于一身,缺点就是兼容性不好,所以应用时需要判断浏览器

合理利用浏览器缓存机制

1.MemoryCache,即在内存中的缓存,从优先级上来说,它是浏览器最先尝试去命中的一种缓存。从效率上来说,它是响应速度最快的一种缓存。

2.Services Worker
Cache,Service Worker 是一种独立于主线程之外的 Javascript 线程。它脱离于浏览器窗体,因此无法直接访问 DOM。这样独立的个性使得 Service Worker 的“个人行为”无法干扰页面的性能,可利用这一点帮我们实现离线缓存、消息推送和网络代理等功能

3.Http缓存,分为强缓存和协商缓存

http缓存的是指:当Web请求抵达缓存时, 如果本地有“已缓存的”副本,就可以从本地存储设备而不是从原始服务器中提取这个文档

强缓存(优先于协商缓存,返回码200):


利用Expires(http1.0,记录缓存过期时间)和Cache-Control(http1.1,记录缓存过期时间)来控制,Cache-Control优先级高于Expires,Expires 使用的是服务器端的时间,要是客户端时间和服务端不同步,就可能造成浏览器本地的缓存无用或者一直无法过期,Cache-Control使用的是使用的是客户端本地时间的计算,所以不会出现上述情况,Cache-Control优先级高于Expires,

协商缓存(返回码304):


利用If-None-Match(请求头)/Etag(响应头)和If-Modified-Since(请求头)/Last-Modified(响应头),If-None-Match和Etag记录的是服务器为每个资源生成的唯一的标识字符串,缓存的数据要是改变了,那么这两个数据就会变,这样可判断缓存到底有没有更新,If-Modified-Since和Last-Modified记录的是服务端的文件最后改变的时间,通过判断这个,可以缓存有没有被更新,Last-Modified有一个缺陷就是只能精确到1s,所以对于精确更高的可能不适用,Etag优先级高于Last-Modified,Etag生成过程需要服务器额外付出开销,会影响服务器性能,所以要看情况使用Etag

强缓存与协商缓存更细致的了解,请参考:

彻底弄懂HTTP缓存机制及原理 <https://www.cnblogs.com/chenqf/p/6386163.html>

HTTP缓存是如何实现 <http://caibaojian.com/http-cache.html>

4.Push Cache

http2阶段的缓存,应用尚处于萌芽阶段,是缓存的最后一道防线。


浏览器只有在 Memory Cache、HTTP Cache 和 Service Worker Cache 均未命中的情况下才会去询问 Push Cache。Push Cache 是一种存在于会话阶段的缓存,当 session 终止时,缓存也随之释放。不同的页面只要共享了同一个 HTTP2 连接,那么它们就可以共享同一个 Push Cache。

合理利用本地存储

1.利用WebStorage


WebStorage提供了一种方式让网站能够把信息存储到本地的计算机上,并在以后需要的时候进行获取。这样一来,当需要用到什么资源时,可以直接在本地存储里获取,而不用发起网络请求等待响应。WebStorage分为localStorage(只支持string类型的存储)与Session
Storage(只支持string类型的存储),Session
Storage在会话结束消失, localStorage永久有效,手动删除才会消失,Session
Storage 和localStorage都遵循同源策略,但是对Session
Storage特殊的一定在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的 Session Storage 内容便无法共享。

2.利用IndexDB


IndexDB运行在浏览器上的非关系型数据库,突破了WebStorage的存储大小限制,支持存储字符串和二进制数据,IndexDB可创建数据库和表,可以被当成一个真正的数据库使用。

使用CDN

CDN全称是内容分发网络,简单的来说,CDN做的事,就是把资源存在离自己最近的服务器里,从而实现就近访问数据,快速获取到需要的数据

CDN 往往被用来存放静态资源(像
JS、CSS、图片等不需要业务服务器进行计算即得的资源),可以将静态资源和主页面置于不同的域名下,避免cookie的携带,这样可以做到优化CDN

CDN的原理请看: 一张图说明CDN网络的原理
<https://blog.csdn.net/coolmeme/article/details/9468743?utm_source=blogxgwz0>

使用服务端渲染

服务端渲染,就是当用户第一次请求页面时,由服务器把需要的组件或页面渲染成 HTML
字符串,然后把它返回给客户端。客户端拿到手的,是可以直接渲染然后呈现给用户的 HTML 内容。


没有服务器渲染,当浏览器解析html文档解析到<script>标签时,就需要停下html渲染,去解析其中的脚本并执行,这整个过程都会阻塞文档解析,直到脚本执行完才会继续解析文档进行渲染。如果js文件的数量和内容都比较大,那么就会造成页面空白,这样是非常不利于用户体验的,服务器渲染就能很好的解决这一问题。

服务端渲染也不是随便就能用的,它加重了服务器的压力,也需要合理使用

CSS优化

1.css选择器:


css是从右往左进行解析的,这也就是说 (ul>li)这种写法,浏览器是先去找到li,再去看每个li的父元素是不是ul,当使用层级较多的选择器时(如:body>div>p>span),会加大浏览器的寻找时间,而我们的原则因当是使浏览器能够尽快的找到相应的元素。所以css选择器方面的优化方案为:

a.避免后代选择符(后代选择器的开销很高)

b.避免链式选择符,避免使用复杂的选择器,层级越少越好

c.避免使用通配符(使用通配符会使浏览器找遍所有的元素)

d.少用标签选择器,尽量用类选择器代替

e.避免不必要的重复

 

2.尽量减少页面重排、重绘:

a.什么是重绘和回流?

部分渲染树(或者整个渲染树)需要重新分析并且节点尺寸需要重新计算。这被称为重排。注意这里至少会有一次重排-初始化页面布局。

由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新。这样的更新被称为重绘。


重绘的代价要比回流小,重绘只涉及样式的改变,不涉及到布局。重绘就好像给人染了一个头发,而回流相当于给人做了一次抽脂手术,回流一定伴随着重绘,而重绘却可以单独出现

b.回流发生的情况:

    1.添加、删除、更新 DOM 节点

    2. 通过 display: none 隐藏一个 DOM 节点-触发重排和重绘

    3.元素位置改变。

    4.元素的尺寸改变(包括:内外边距、边框厚度、宽度、高度等属性的改变)。

    5. 内容改变。

    6.页面渲染器初始化。

    7.浏览器窗口尺寸改变。

    8.添加一个样式表,调整样式属性

    9.用户行为,例如调整窗口大小,改变字号,或者滚动。

c.触发回流的属性:

     1.盒子模型相关属性: width ,height ,padding ,margin ,display ,border-width ,border

     2.定位属性及浮动: top ,bottom ,left ,right ,position ,float ,clear

     3.改变节点内部文字结构:

       text-align, overflow-y ,font-weight ,overflow, font-family,
line-height, vertival-align ,white-space,font-size

d.重绘发生的情况:

重绘发生在元素的可见的外观被改变,但并没有影响到布局的时候。比如,仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)

e.触发重绘的属性有:

color,border-style,border-radius ,visibility,text-decoration ,background
,background-image ,background-position ,background-repeat,background-size
,outline-color ,outline ,outline-style ,outline-width ,box-shadow

f.减少页面重排、重绘的方法:

避免逐条改变样式,使用类名去合并样式,尽量将样式写在单独的css文件里面

通过 visibility:hidden 隐藏一个 DOM 节点

参考文档:

回流(reflow)与重绘(repaint) <https://www.cnblogs.com/dll-ft/p/5810639.html>

重绘和重排 <http://www.voidcn.com/article/p-rmbuixen-bqe.html>

 

3.减少css阻塞:


当我们在html时,总是在解析到link标签或style标签时,CSSDOM才会开始构建,这个构建过程会导致DOM解析的阻塞,所以为了减少阻塞时间,我们需要尽快完成加载(启用CDN),尽早完成加载(在head元素中引用css相关标签)

JS优化

1.减少JS阻塞


页面构建dom树的过程,即从上到下解析HTML文档生成DOM节点树,当解析到<script>标签时,会解析其中的脚本(对于外链的JavaScript文件,需要先加载该文件内容),然后立即执行,这整个过程都会阻塞文档解析,直到脚本执行完才会继续解析文档。如果js文件的数量和内容都比较大,那么就会造成页面空白,所以为了避免这一状况,应该把
<script>标签放在</body>标签前面,而不是放在<head>标签里,要使用async(异步加载,脚本加载完立刻执行)和defer(异步加载,文档解析完执行)

2.在异步任务中实现 DOM 修改时,把它包装成 micro 任务(微任务)

事件循环一般是这样,先处理Macro-task(宏任务),再处理micro 任务,micro 任务处理完后面紧跟着就是渲染的步骤,然后更新界面,处理Web
work任务。包装成 micro 任务,这样不用等新的一轮事件循环,直接渲染呈现

3.Dom方面(从减少页面回流方面来考虑)

减少Dom操作,缓存dom变量(比如var a=document.querySelector("#demo");)

避免循环更改dom,在更改时创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到相应dom中

4.使用异步更新策略(我也没看懂。。。)

使用图片懒加载

图片懒加载,就是当图片出现在浏览器的可视区域内时,设置图片真正的路径,让图片显示出来。当一个页面中由许多图片时,使用懒加载,可大大提高页面性能。


具体完成过程为,先给图片一个假的src,不让图片加载,通过监听滚动时间+函数节流,来完成判断元素距离可视区域顶部的高度,要是高度差>=0,那么就将正确的src赋给图片,图片完成加载。

 

参考文档:前端性能优化原理与实践 <https://juejin.im/book/5b936540f265da0a9624b04b>(买了真的很值)