前端工程
项目优化
加载优化
不同于传统 GUI 开发应用先下载后使用的方式,网页应用是动态增量下载的
因而页面加载是对用户使用体验影响最大的部分,超过 3s 的加载时间会导致大量用户的流失。
提高加载速度,即在最短的时间内获取用户需要使用到的资源,包括对资源的压缩和控制资源的获取两大方面。
资源方面
图片资源
- 小图资源:对于常规小图采用 BASE64 编码,对于图标资源转为字体图标或 svg 图标,以减少资源请求
- 大图资源:开启资源压缩,或使用预览图片用于原图加载的缓冲
代码资源
- 使用 tree shaking 移除无效代码
- 开启压缩减少代码体积
- 使用 SplitChunks 拆分依赖
网络方面
配置 CDN
- 对静态资源或静态页面开启 CDN
- 针对不同的资源类型使用不同的域名(并避免 cookie 的携带)
配置缓存
- 频繁修改的资源:使用协商缓存,配置
Cache-Control: no-cache并配合Etag检测是否使用缓存 - 长期不变的资源:使用强缓存,配置
Cache-Control: max-age=xxx - 无需缓存的资源:禁用缓存,配置
Cache-Control: no-store
开启 HTTP2
- 多路复用:提高 TCP 连接使用效率
- 头部压缩:减少数据请求大小
服务端
- DNS 解析使用 IP 循环
- 开启反向代理实现负载均衡
- 开启 GZIP 压缩减少响应体积
加载方面
标签位置
- 样式文件:置于页面头部,CSS 文件的加载不会阻塞 DOM 的解析
- 脚本文件:置于页面底部,JS 文件的加载会阻塞页面的解析和渲染
预处理
- DNS 预获取:
<link rel="dns-prefetch" href="//www.xxx.com" /> - 资源预加载:
<link rel="preload" href="https://www.xxx.com" as="style" />- 用于预先加载当前页面需要使用的资源,提高在后续使用时的效率
- 资源预获取:
<link rel="prefetch" href="https://www.xxx.com" />- 用于预先获取接下来需要使用的资源并缓存 5 分钟,提高页面切换时的效率
- 资源预渲染:
<link rel="prerender" href="https://www.xxx.com" />- 实验中的属性,预先获取资源并在屏幕之外进行渲染,提高渲染时的效率
懒加载
- 懒加载:在使用时再加载
- 路由切换:常见于 SPA 应用
- 滚动加载:当模块滚动到可视区域时进行加载(如
<img loading="lazy" />)
- 懒执行:在使用时再执行,通常用于耗时逻辑,一般通过事件唤醒
首屏加载
首屏加载主要指优化白屏时间以提升用户体验
- 对于需要服务请求的页面:可以使用 loading 或骨架屏缓解用户等待体验
- 对于无需服务请求的页面:可以使用服务端渲染或静态页面
运行优化
某些时候,可能需要使用动画效果提升页面表现,或者渲染大量的列表元素用于内容展示
前者往往容易频繁的触发页面的回流重绘降低网页流畅度,后者可能导致页面短时间卡顿。
渲染优化
- 独立图层:独立图层的布局互不干扰,可以提高渲染效率
- 有 3d
transform; - 对
opacity、transform、filter应用了动画或过渡 - 设置
will-change: opacity|transform|top|left|right|bottom
- 有 3d
- 减少回流
- 使用
transform、opacity实现动画效果,会创建独立图层并获得 GPU 加速 - 使用
requestAnimationFrame实现动画 - 对于多次操作的 DOM 元素先离线(
display: none),等处理完毕后再展示
- 使用
批量渲染
对于一次性渲染大量元素,可以使用 requestAnimationFrame 控制渲染频率,使用 DocumentFragment 对多个元素进行一次插入
js
// <div id="wrap"></div>
function render() {
const total = 1e4;
const once = 1e2;
let nums = 0;
function append() {
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const div = document.createElement("div");
div.innerText = Math.random();
fragment.appendChild(div);
}
wrap.appendChild(fragment);
nums += once;
if (nums < total) {
requestAnimationFrame(append);
}
}
append();
}
render();虚拟渲染
对于大量数据渲染的列表,若每项高度可计算,可以仅渲染可视区域以及滚动缓冲部分,对于其他不可视部分,使用一个计算后的空白盒子进行支撑。
计算优化
使用 web worker 将耗时的操作交给其他线程,减轻主线程压力