性能优化
评测点
- 评测点:首屏速度 白屏时间
- 从 http 请求数量
- http 请求体积
- dom 操作层面
- dom loaded事件
React 项目性能优化
先分析
- bundle 分析 webpack-bundle-analyzer
- chrome performace
- react profiler 分析 render duration
代码层面
- 避免不必要的 render
- shouldComponentUpdate/React.PureComponent 为 class 组件服务
- 浅比较(比较对象的引用)
- React.memo(Comp) 为函数组件服务 对 Props 进行浅比较
const OtherComponent = React.memo(()=>{ ... }); - 善用 React.useMemo
const App = (props)=>{ const [boolean, setBoolean] = useState(false); const [start, setStart] = useState(0); // 这是一个非常耗时的计算 // 调用 setBoolean 组件会重新 render,又会执行这个耗时的运算 const result = computeExpensiveFunc(start); // 改进,当 start 变化时,才允许计算新的 result const result = useMemo(()=>computeExpensiveFunc(start), [start]); }- 合理使用 React.useCallback
// 虽然 OtherComponent 已经用 React.memo 包裹起来了,但在父组件每次触发 setBoolean 时, OtherComponent 仍会频繁 render // 因为父级组件 onChange 函数在每一次 render 时,都是新生成的,导致子组件浅比较失效。通过 React.useCallback,我们可以让 onChange 只有在 state 变化时,才重新生成 const OtherComponent = React.memo(()=>{ ... }); const App = (props)=>{ const [boolan, setBoolean] = useState(false); const [value, setValue] = useState(0); // 错误 ❌ const onChange = (v)=>{ axios.post(`/api?v=${v}&state=${state}`) } // 正确 ✔️ const onChange = React.useCallback((v)=>{ axios.post(`/api?v=${v}&state=${state}`) }, [state]) return ( <div> {/* OtherComponent 是一个非常昂贵的组件 */} <OtherComponent onChange={onChange}/> </div> ) }
- shouldComponentUpdate/React.PureComponent 为 class 组件服务
打包优化
- code spliting (SplitChunksPlugin) 默认开启
- tree shaking 默认开启
分析
性能优化层面
- 缓存层面
- 网络层面
- 渲染层面
DOM 层面
- 缓存DOM元素,提高页面性能
- CSS3 transform 取代传统DOM节点操作 使用GPU硬件加速
- 减少reflow/repaint
- 避免不必要的dom操作 使用domfragment
网络层面
- link preload prefetch
- script async defer script标签再也不要放到页脚了 笑
- 懒加载 code spliting / 图片懒加载
- 压缩混淆css/js -> 减小http体积
- 图片 使用css精灵图/字体图标/base64
- 缓存 pwa / http cache
优化网络
- 减少资源体积
- gzip 压缩
- 打包优化
- 图片格式
- 使用 HTTP2
- 加快请求速度
- HTTP2 多路复用
- 减少请求
- 缓存
- 强缓存和协商缓存
- CDN
- 本地存储
- 图片
- 内联 base64
- 雪碧图
- 异步加载
- script async/defer
- 缓存
JS 性能优化
对 JS 性能影响最大的就是内存分配、垃圾收集和作用域访问。
- 目的
- 更少的内存占用
- 编译时间少
- 不要卡死事件队列
- 不要让浏览器卡顿
- 不要让浏览器响应编码
- 浏览器是单进程的
- 数据结构和算法的优化
- 使用防抖和节流
- 使用 requestFrame,把任务切分到每一帧
- 使用 Worker,不在主线程进行大量运算
- 使用 web assembly
渲染层面
- 传统的服务端渲染存在的弊端?
- 分块传输
- http 1.1 中引入了一个 http 首部,Transfer-Encoding:chunked
- 这个首部标识了实体采用chunked编码传输,chunked编码可以将实体分块儿进行传输,并且chunked编码的每一块内容都会自标识长度
- 如果需要多个数据,而多个数据均返回较慢的话。可以处理完一块就返回一块,让浏览器尽早的接收到html,可以先行渲染
- bigPipe
- 回填的思路
- 为什么不用ajax去请求后端,拉数据,劣势是什么?
服务端配置
HTTP 缓存
HTTPS
HTTP2
CDN 部署
服务端渲染 SSR
React 服务端渲染
Vue 服务端渲染
预渲染
和 SSR 比
实现方案
前端渲染性能
卡顿侦测
优化方案
减少计算
并行计算
- WebGL
- Web Worker
代码优化
- 优化算法,调整结构
原理
http 的问题
- 重复传输 header
- 消息主体都会经过gzip压缩,或者本身传输的就是二进制文件
- 状态行和头部没有经过任何压缩,以纯文本传输。而且大部分http的headers内容都是重复的
- 明文传输 被中间人劫持
异步加载第三方内容
(function(){
var script,
scripts = document.getElementByTagName('script')[0];
function load(url){
script = document.createElement('script');
script.async = true;
script.src = url;
scripts.parentNode.insertBefore(script, scripts);
}
load('//apis.plugin.js')
load('//apis.plugin.js')
load('//apis.plugin.js')
})()
专栏 + 小册
- 你不知道的前端性能优化技巧 - 慕课专栏
- 前端性能优化原理与实践 - 掘金小册
- 优化的概念
- 性能优化工具
- 性能监测
- 可视化工具
- Performance
- LightHouse
- W3C 性能 API
- 可视化工具
- 网络部分
- 请求过程的优化
- Gzip压缩原理
- 构建工具性能调优
- DNS Prefetch
- 图片加载优化
- 减少网络请求
- 本地存储
- 请求过程的优化
- 缓存部分
- CDN 缓存
- 本地缓存
- 渲染部分
- 浏览器的渲染机制
- CSS 性能方案
- JS 性能方案
- 服务端渲染的探索与实践
- 避免首屏一片空白
- DOM 性能优化
- Event Loop 力挽狂澜
- 重绘与回流
- 浏览器的渲染机制
- 应用实践
- 防抖节流
- 服务端渲染
- 懒加载
- React 优化
题目
1 面试官:webpack的gzip和nginx的有什么关系?
nginx没有开启gzip压缩,webpack打包出的.gz文件是用不到的2.nginx开启了gzip,nginx查找静态资源是否存在已经压缩好的gzip压缩文件,如果没有则自行压缩(消耗cpu但感知比较少)3.nginx开启gzip压缩,webpack打包出的.gz文件被找到,提前(打包)压缩直接使用,减少了nginx的压缩损耗
2 Expires和Cache-control优先级
Expires - 具体过期时间 Cache-control - 相对过期时间
若两者同时存在,取Cache-control
3 面试官:Cache-control有哪些属性了解过吗
no-cache public 可以被任何缓存区缓存 private 只能在浏览器中被缓存 代理服务器不可以缓存 max-age 相对过期时间 以秒为单位 s-maxage ?
4 面试官: Last-Modified和ETag的区别
Last-Modified计算方式比Etag简单,算法难度不一样
but 如果一个文件在1s内更新了多次,Last-Modified就不靠谱了,文件就被缓存住了
5 说说cdn原理 选取最近位置进行请求,节省对源站的消耗(回源)
6 图片转Base64是为了什么
小的图片 使用base64编码 可以减少一次图片的网络请求
大的图片 base64编码会和html混在一起 html内容会变大 因此webpack url-loader提供Limit的功能
而且base64编码的图片不能像正常的图片进行缓存 但是写在css里面 css文件可以缓存
7 面试官:说说 defer 和 async 的使用场景
- defer 一边下载,等待dom解析完才执行,早于 DOMContentLoaded
大多数情况 对加载顺序有要求 都是要defer
async 下载完便执行,下载过程和 dom 解析并行
js执行都阻塞DOM渲染
async适合不依赖dom,第三方资源
8 面试官:preload 和 prefetch 的共同点和不同点
preload 优先级高
prefetch 浏览器空闲的时候 才会请求
9 http keep-alive / tcp keep-alive
HTTP Keep-Alive是一项功能,它允许HTTP客户端(通常是浏览器)和服务器(网络服务器)通过同一TCP连接发送多个请求/响应对。这减少了第二,第三,... HTTP请求的延迟,减少了网络流量等。
TCP keepalive是完全不同的野兽。它通过发送小数据包保持TCP连接打开。此外,在发送数据包时,这是一种检查,以便在连接断开时立即通知发送方
10 为什么HTTPS选择对称加密和非对称加密
非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心,而对称加密快很多,看来必须得用对称加密
11 HTTPS 必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?
这也是我当时的困惑之一,显然每次请求都经历一次密钥传输过程非常耗时,那怎么达到只传输一次呢?
用session就行。
服务器会为每个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下,之后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了!