公司的技术课程,还挺全面的,从网络传输,缓存配置,静态资源加载,运行时优化四个方面进行了阐述,做了个小笔记
网络传输
开启HTTP2
- 🔥多路复用,多个请求复用一个TCP连接
- 二进制传输,解析高效,体积小
- 消息头压缩,压缩Header体积,建立字典,用索引号表示重复的字符串
- 服务端push(一般不用,可以用preload替代
CDN部署静态资源
- 用户先向edge发请求,如果edge找不到,再往上级找,直到请求到root
- 找到资源时,同时在各个edge上缓存该资源
- 所以资源直接上传到root
- 冷启动问题:使用预热
- CDN不过期问题:
- 配置较短的过期时间,或者手动刷新CDN
- 与客户端缓存配合:CDN节点缓存等于客户端强缓存的时间
DNS预解析
dns-prefetch
:针对一些小众网站,dns解析可能会长达0.5秒提前建立网络连接
preconnect
:提前做好DNS,TCP,SSL的过程,到时直接传数据即可域名收敛:把静态资源部署到尽可能少的域名下
充分发挥HTTP2的多路复用特性
最大化节省DNS解析,TCP建连等网络成本
之前提倡域名发散,是因为HTTP1.1时代,浏览器对同域名请求有并发限制
使用brotil压缩:优于gzip压缩
优化https:多次握手,TLS相关算法会造成额外开销,导致相比http性能差距大【有点硬核,略过】
使用缓存
- DNS缓存:
- 解析路径:浏览器缓存 → 操作系统缓存 → DNS缓存
- 宿主浏览器缓存,以优先级排序
- memory缓存:优先级最高,不是所有资源都能memory缓存,如js
- cache API缓存:如PWA
- http缓存:强缓存,协商缓存
- push缓存:HTTP2的Server push开启时才有的缓存,略过
- 运行时缓存:与业务耦合较重,需要因地制宜优化
- Cookie:存放简单数据
- LocalStorage:存储一定体积的数据
- IndexDB:存放大量结构化的数据
- Memory:存放临时数据
静态资源加载
资源预加载
- 预加载当前页面资源
link preload
- 预加载下级页面的资源
link prefetch
:空闲时才会做fetch - 直接渲染好二级页面:
link prerender
:性能损耗大
- 预加载当前页面资源
HTML加载
- 控制HTML体积
- 传输体积不要超过30kb
- 减少DOM节点和属性
- 谨慎使用内联
- 骨架屏
- 控制HTML体积
JS加载
优化加载方式
- 传统JS加载:同步执行,阻塞DOM生成
- defer加载:立即下载资源,DOM生成完之后才会执行
- async加载:立即下载资源,异步执行,不阻塞DOM
type="module"
:支持ES Module的同时自带了defer的特性type="module" async
:支持ES Module的同时自带了async的特性
生产环境不建议使用 type=”module”,一是因为兼容性不好,二是因为串行加载,限制了速度,开发环境下配合vite,snowpack不错
优化文件体积
- 压缩:terser压缩文本代码,gzip二进制压缩
- 按需加载,code splitting,把不重要的代码单独拆分出来,需要了再去加载(dynamic import
- 精准控制polyfill:通过browsrelist申明宿主环境,只注入需要的polyfill
- Tree Shaking:只有ES Module才可以,同时需要对副作用进行申明
- 谨慎引入三方库
优化网络请求
动静分离打包:
- 动:经常改动的业务,UI代码
- 静:common的公共库,很少进行改动
- 目的:充分利用HTTP缓存,对于静的资源,用户没有二次下载成本
主次分割:
主要模块
major
:可以特指首屏依赖的模块,需要最高优先级处理,保证体积和逻辑尽可能少,首先加载,获得最有体验次要模块
minor
:指非首屏区域的内容,允许这部分出现的稍晚和页面闪烁
优化网络请求-尽可能利用缓存
- 文件指纹:利用hash来生成文件名,进行版本控制
- 缓存时长控制
CSS加载
- 合理选择加载方式
- 内联加载:很快,但是造成HTML体积增大,且HTML缓存时间较短
- link标签引入
- CSS in JS:JS动态注入样式,用于业务强相关的需求
- 优化文件体积
- 压缩:使用cssnano + gzip
- 精准控制prefix:同样通过browserlist
- 去除冗余样式:使用PurifyCSS或CSS Module
- CSS加载:与JS类似,动静分离与主次分割
- 优化网络请求:与JS一致
- 合理选择加载方式
图片加载
- 控制加载时机
- 关键图片:大图片使用 preload 预加载,小图片使用base64内联
- 次要图片:可以选择懒加载
- 图片格式:
- 矢量图:svg
- 像素图:能webp就webp,不能则
- 颜色少,层次分明:png
- 颜色,渐变多,复杂:jpg
- 不同设备加载不同size:媒体查询和 picture标签
- 如果关键大图体积较大,可以拆分成一个核心图和多个边缘小图
- 控制加载时机
字体加载
- 控制加载时机:与JS,CSS相似
- 控制加载策略
- 关键字体配置为
font-display: block
,意思是等到字体下载完才渲染 - 次要字体配置为
font-display: swap
,意思是先用默认字体渲染,字体下载完再进行替换
- 关键字体配置为
- 字体格式选择:PC使用
woff
,移动端使用ttf
- 字体裁剪:
- 使用工具裁剪,生成子集,如 fontmin,subfont(只适用于静态文本
- 生成字体时,只引入我们需要的font-weight
- 缓存策略:与JS,CSS相似
运行时优化
- HTML
- 减少DOM元素数量
- 使用
innerHTML
来增删多个元素 - 使用
getElementByXX
来选择元素
- JS
- 网络请求提前:与首屏渲染强相关的请求,可以提前发起,放到JS第一行,或者提前到HTML中发起
- 避免出现CPU高占用
- 合理处理long task,task拆分,异步执行,复用结果,使用 web worker等
- 减少触发频率:防抖,节流
- JS动画使用
requestAnimationFrame
而不是setInterval
- 合理使用内存
- 避免内存泄漏:
- 全局变量无法被GC
- 对DOM始终存在引用
- 闭包引用自由变量
- 使用事件委托:绑定相同事件到多个DOM上时,可以绑定到父元素上,通过事件冒泡来处理
- 使用缓存:JS内部缓存和宿主缓存(参考第二章
- 避免内存泄漏:
- CSS
- 不使用
@import
:会导致额外的加载时间 - 使用现代布局方案:flex和grid
- 避免高频触发重绘,重排
- 绝对定位
- 提前标明元素的宽高,避免后续的重排
- 优先使用CSS实现动画
- 不使用
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!