前端性能优化

网络层面的优化
1.webpack 性能调化与 Gzip 原理。
webpack 的优化的瓶颈:构建时间长,打包体积大。
构建时间长的方案
不要让loader做太多事情,用include或exclude避免不需要的转译(node_modules);开启缓存将转译结果缓存至文件系统loader: 'babel-loader?cacheDirectory=true')。
不要放过第三方库,DllPlugin这个插件会把第三方库单独打包到一个单纯的依赖库的文件中。这个依赖库不会跟着你的业务代码一起被重新打包,只有当依赖自身发生版本变化时才会重新打包。
将loader由单进程转为多进程,Happypack把任务分解给多个子进程去并发执行。手动创建进程池,问号后面的查询参数指定了处理这类文件的HappyPack实例的名字,new HappyPack id 和 threadPool指定进程池
打包体积大的方案
webpack-bundle-analyzer 文件结构可视化,找到导致体积大的原因。
删除冗余代码,webpack4中配置 optimization.minimize 和 minimizer 字定义压缩删除相关操作。
按需加载require.ensure(dependencies, callback, chunkName)
Gzip 压缩
开启 Gzip,在 request hheaders中加上:accept-encoding:gzip
原理:找出重复出现的字符串、临时替换它们从而使整个文件变小。
2.图片优化
不同场景选择不同类型的图片
JPEG/JPG - 有损压缩,背景图、轮播图、Banner图。
PNG - 支持透明,体积大。色彩表现力强,对线条的处理更加细腻。小Logo、颜色简单对比度强的透明小图。
SVG - 文本文件、不失真、体积小。写入HTML、写入独立文件引入HTML。
Base64 - 文本文件、依赖编码、小图标解决方案。非常小的Logo。
CSS Sprites - 将小图标和背景合并到一张图片上,利用背景定位显示其中的部分。
WebP - 旨在加快图片加载速度的图片格式。.jpg_.webp 格式来匹配不支持的情况。
3.浏览器缓存
浏览器缓存机制由四个方面,按照获取资源请求的优先级一次排列:
1.Memory Cache
内存中的缓存。Base64 格式的图片。几乎永远可以被塞进去。可视作浏览器为了节省开销的“自保行为”。
2.Service Worker Cache
独立于主线程之外的js线程。有install、active、working 三个阶段。一旦Service Worker被install,它将始终存在,只会在active与working之间切换,除非我们主动终止它。
必须以 https 协议为前提。
3.HTTP Cache
强缓存在缓存时间内不向服务器发起请求,过期之后才会发起请求。
cache-control :max-age=31536000
max-age 控制资源的有效期,时间长度内是有效的,单位是秒。
Cache-Control 的 max-age 比 expires 优先级更高。
no-cache 绕开浏览器,直接去向服务器确认该资源是否过期。
no-store 不使用任何缓存策略,只允许你直接向服务器发送请求、并下载完整的响应。
协商缓存:浏览器和服务器合作之下的缓存策略
如果服务器端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,这种情况下网络请求对应的状态码是 304。
首次请求随着 Response Headers返回Last-Modified,随后请求会带上 If-Moodified-Since 的时间戳字段,比较两者的时间去执行对应的操作。变了会发起一个完整的响应内容,并在Response Headers返回新的Last-Modified值;否则返回304响应,不添加Last-Modified字段。弊端:内容没变也会重新请求;修改文件过快没发起请求。
Etag是由服务器未每个资源生成的唯一的标识字符串(基于文件内容编码的),Etag能够精准感知文件的变化。
首次请求可以在Response Headers获得一个最初的标识符字符串,下次请求在请求头带上值相同的、名为 if-None-Match 的字符串供服务端对比。
4.Push Cache
HTTP2 在 server push 阶段存在的缓存。
在以上都没有命中才会去询问 Push Cache;
它存在于会话阶段的缓存,当session终止时,缓存也随之释放;
不同页面只要共享了同一个 HTTP2 连接,那么他们就可以共享一个 Push Cache
4.本地储存
Cookie
为了维持状态;附着在 HTTP 请求上,在浏览器和服务器之间传输。
劣势:Cookie 不够大,只有 4KB;过量的 Cookie 会带来巨大的性能浪费,同一域名下的所有请求,都会写到Cookie。
Local Storage
持久化的本地储存,使其消失的唯一办法手动删除。
储存 Base64 格式的图片字符串;不常更新的 CSS、JS 等资源。
Session Storage
会话结束时,内存内容被释放。
储存上次访问的 URL 地址。
Web Storage
特性:
存储量5-10M。
位于浏览器端,不与服务端发生通信。
API:
储存:setItem()
读取:getItem()
删除:removeItem()
清空:clear()
IndexedDB
一个运行在浏览器上的非关系型数据库。>250M 可以存储字符串、二进制数据。
可以看做是LocalStorage的一个升级。
5.CDN 缓存与回源
CDN 指的是一组分布在各个地区的服务器。这些服务器储存着数据的副本,因此服务器可以根据哪些服务器与用户距离最近,来满足数据的请求。CDN 提供快速服务,较少受高流量影响。
核心:缓存 回源。“缓存”就是我们把资源 copy 一份到 CDN 服务器上这个过程,“回源”就是CDN发现自己没有这个资源(一般是缓存数据过期了),转头向根服务器去要这个资源的过程。
CDN 往往被用来存放静态资源。(CSS、JS、Image)
CDN 域名和服务器域名不同。
渲染层面
1.服务端渲染
SSR 主要用于解决单页应用首屏渲染慢以及SEO问题,但同时:提高了服务器压力,吃CPU,内存等资源,优化不好提高成本。
Vue是如何实现服务端渲染的呢?
一是这个 renderToString() 方法(把Vue实例转化为真实DOM的关键方法);
二是把转化结果“塞”进模板里。(res.end 把渲染出来的真实DOM字符串插入HTML模板中)
2.浏览器渲染 - CSS、JS性能方案
每个页面首次渲染都经历了 解析HTML - 计算样式 - 计算图层布局 - 绘制图层 - 整合图层得到页面。HTML构建DOM树,CSS构建CSSOM树,CSSOM与DOM结合得到渲染树,最后浏览器以布局渲染树去计算布局,绘制图像。
CSS 选择器是从右到左进行匹配的。(避免使用通配符;用类选择器代替标签选择器;不要画蛇添足用id和class选择器;减少嵌套)。
CSS 的阻塞,需要尽早(放在 head 标签里)和尽快(启用 CDN 实现静态资源加载速度优化)地下载到客户端,以便缩短首次渲染的实践。
JS 的阻塞,JS 引擎抢走了渲染引擎的控制权。asyncdefer模式加载都是异步的,async 是立即执行的(用于DOM和脚本依赖不强),defer 是推迟执行的(等整个文档解析完成时,用于脚本依赖DOM和其他脚本的执行结果)。
3.DOM优化原理与基本思路
当我们用JS操作DOM时,本质上时JS引擎和渲染引擎之间进行了“跨界交流”,依赖了桥接接口作为“桥梁”。减少DOM操作。
我们对DOM修改会引发它外观上的改变时,就会出发回流(几何尺寸变化)或重绘(样式变化)。
减少DOM操作:缓存变量;DOM Fragment。
4.事件循环和异步更新策略
事件循环优化:当我们需要在异步任务中实现DOM修改时,把它包装成 micro 任务时相对明智的选择(不需要多消耗一次渲染,不需要等待下一事件循环)。macro - mincro - render。
异步更新:把任务塞到异步任务队列里,在JS层面被批量执行完毕。到渲染时,它仅仅需要针对有意义的计算结果操作一次DOM。(避免过度渲染
使用Vue.nextTick()是为了可以获取更新后的DOM。在同一事件循环中的数据变化后,DOM完成更新,就会执行Vue.nextTick()的回调。过程是同一事件循环中的代码执行完毕 -> DOM 更新 -> nextTick callback触发。
5.回流和重绘
触发回流:改变DOM元素的几何属性;改变DOM树的结构;获取特定的值(即时计算得到)。
JS变量的形式缓存起来。
避免逐条改变样式,使用类名去合并样式(el.classList.add('basic_style'))。
将DOM离线(display = 'none' ..添加样式.. display = 'block')
Flush队列(自己缓存一个flush队列,把任务塞进去,到一定时间再出队)。
应用篇
1.优化首屏体验 - Lazy-Load
图片懒加载
<img class="pic" alt="加载中" data-src="./images/1.png"> // 当前可视区域的高度 window.innerHeight || document.documentElement.clientHeight // 元素距离可视区域顶部的高度 getBoundingClientRect().top // 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出 imgs[i].src = imgs[i].getAttribute('data-src') num = i + 1
2.事件的节流和防抖
这两个东西都以闭包的形式存在。
它们通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率。
节流的中心思想:在某段时间内,不管你触发了多少次回调,我都只认第一次,并在计时结束时给予响应。(本次触发的时间-上次触发的时间 >= 设定的时间间隔阈值则执行回调
防抖的中心思想:我会等你到底。在某段时间内,不管你触发了多少次回调,我都只认最后一次。(每次事件被触发时,都去清除之前的旧定时器,设立新定时器
性能检测
Performance
LightHouse
W3C性能API
 
 
缓存解决方案
强缓存
协商缓存
http缓存流程图
当我们的资源内容不可复用时,直接为 Cache-Control 设置 no-store,拒绝一切形式的缓存;否则考虑是否每次都需要向服务器进行缓存有效确认,如果需要,那么设 Cache-control 的值为 no-cache;

否则考虑该资源是否可以被代理服务器缓存,根据其结果决定时设置为 private 还是 public;然后考虑该资源的过期时间,设置对应的 max-age 和 s-maxage 值;最后,配置协商缓存需要用到的 Etag、Last-Modified 等参数。
posted @ 2021-08-06 14:19  温少昌  阅读(254)  评论(0编辑  收藏  举报