🚀
性能优化
7 道题目
难度筛选:
加载优化:
1. 路由懒加载 / 代码分割
2. 图片懒加载(Intersection Observer)
3. 资源预加载(preload / prefetch)
4. CDN 加速静态资源
5. 开启 gzip / br 压缩
渲染优化:
1. 减少 DOM 操作,使用虚拟 DOM
2. 使用 transform 代替 top/left 做动画(GPU 加速)
3. 防抖和节流
4. 虚拟列表(react-window / vue-virtual-scroller)
构建优化:
1. tree-shaking 移除无用代码
2. 代码分割(dynamic import)
3. 图片压缩 + WebP 格式
4. 合理设置缓存策略
1. 路由懒加载 / 代码分割
2. 图片懒加载(Intersection Observer)
3. 资源预加载(preload / prefetch)
4. CDN 加速静态资源
5. 开启 gzip / br 压缩
渲染优化:
1. 减少 DOM 操作,使用虚拟 DOM
2. 使用 transform 代替 top/left 做动画(GPU 加速)
3. 防抖和节流
4. 虚拟列表(react-window / vue-virtual-scroller)
构建优化:
1. tree-shaking 移除无用代码
2. 代码分割(dynamic import)
3. 图片压缩 + WebP 格式
4. 合理设置缓存策略
查看答案即标记为已答
虚拟列表:只渲染可视区域内的列表项,而非全部。适用于大数据量列表。
实现原理:
1. 计算可视区域能显示的项数
2. 根据滚动位置计算起始索引
3. 只渲染
4. 用 padding-top 或 transform 偏移,模拟完整列表位置
库:react-window、react-virtualized、vue-virtual-scroller。
注意:不定高需要动态测量和缓存高度。
实现原理:
1. 计算可视区域能显示的项数
visibleCount = containerHeight / itemHeight2. 根据滚动位置计算起始索引
startIndex = Math.floor(scrollTop / itemHeight)3. 只渲染
startIndex 到 startIndex + visibleCount 的项4. 用 padding-top 或 transform 偏移,模拟完整列表位置
// 核心逻辑
const visibleItems = items.slice(start, end);
container.style.paddingTop = start * itemHeight + 'px';
container.style.height = totalHeight + 'px';库:react-window、react-virtualized、vue-virtual-scroller。
注意:不定高需要动态测量和缓存高度。
查看答案即标记为已答
懒加载:延迟加载非关键资源,直到需要时才加载。
图片懒加载方案:
1. 原生 loading 属性(最简单):
2. Intersection Observer:
3. 滚动事件监听(旧方案,性能差)
建议:优先使用原生
图片懒加载方案:
1. 原生 loading 属性(最简单):
<img src="image.jpg" loading="lazy" />2. Intersection Observer:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));3. 滚动事件监听(旧方案,性能差)
建议:优先使用原生
loading="lazy",兼容性不够时用 Intersection Observer。 查看答案即标记为已答
核心指标:
• FCP(First Contentful Paint):首次有内容绘制
• LCP(Largest Contentful Paint):最大内容绘制(<2.5s 为佳)
• TTI(Time to Interactive):可交互时间
• CLS(Cumulative Layout Shift):布局偏移
优化手段:
1. SSR / SSG:服务端渲染或静态生成,减少客户端渲染等待
2. 关键 CSS 内联:首屏 CSS 直接嵌入 HTML
3. 预加载关键资源:
4. 字体优化:font-display: swap,避免 FOIT
5. 图片优化:WebP、响应式图片、LCP 图片优先加载
6. 减少第三方脚本阻塞渲染
• FCP(First Contentful Paint):首次有内容绘制
• LCP(Largest Contentful Paint):最大内容绘制(<2.5s 为佳)
• TTI(Time to Interactive):可交互时间
• CLS(Cumulative Layout Shift):布局偏移
优化手段:
1. SSR / SSG:服务端渲染或静态生成,减少客户端渲染等待
2. 关键 CSS 内联:首屏 CSS 直接嵌入 HTML
3. 预加载关键资源:
<link rel="preload">4. 字体优化:font-display: swap,避免 FOIT
5. 图片优化:WebP、响应式图片、LCP 图片优先加载
6. 减少第三方脚本阻塞渲染
查看答案即标记为已答
构建速度优化:
1.
2.
3.
4.
5.
产物体积优化:
1.
2.
3.
4.
5.
6. 分析工具:
1.
cache: { type: 'filesystem' } — 持久化缓存2.
thread-loader — 多线程编译3.
include/exclude — 缩小 loader 范围4.
resolve.alias — 减少模块搜索5.
externals — 排除大型库,用 CDN 引入产物体积优化:
1.
SplitChunksPlugin — 代码分割2.
TerserPlugin — JS 压缩3.
MiniCssExtractPlugin — CSS 提取4.
ImageMinPlugin — 图片压缩5.
gzip/brotli 压缩6. 分析工具:
webpack-bundle-analyzer 查看答案即标记为已答
Web Worker:在后台线程中运行 JS,不阻塞主线程 UI 渲染。
使用方式:
限制:
• 不能操作 DOM
• 不能使用 window 对象(用 self 代替)
• 通信是异步的(postMessage,数据会被结构化克隆)
适用场景:大数据处理、复杂计算、图片处理、加密解密。
SharedArrayBuffer + Atomics 可实现零拷贝共享内存。
使用方式:
// main.js
const worker = new Worker('worker.js');
worker.postMessage({ data: largeArray });
worker.onmessage = (e) => console.log(e.data);// worker.js
self.onmessage = (e) => {
const result = heavyComputation(e.data);
self.postMessage(result);
};限制:
• 不能操作 DOM
• 不能使用 window 对象(用 self 代替)
• 通信是异步的(postMessage,数据会被结构化克隆)
适用场景:大数据处理、复杂计算、图片处理、加密解密。
SharedArrayBuffer + Atomics 可实现零拷贝共享内存。
查看答案即标记为已答
防抖(debounce):事件停止触发 n 秒后执行一次。
场景:搜索框输入、窗口 resize 结束后重新计算布局
节流(throttle):n 秒内只执行一次。
场景:滚动事件、拖拽、射击游戏
区别:
• 防抖:等待停顿后才执行(如搜索建议)
• 节流:保持固定频率执行(如滚动加载)
简单实现:
防抖:
节流:
场景:搜索框输入、窗口 resize 结束后重新计算布局
节流(throttle):n 秒内只执行一次。
场景:滚动事件、拖拽、射击游戏
区别:
• 防抖:等待停顿后才执行(如搜索建议)
• 节流:保持固定频率执行(如滚动加载)
简单实现:
防抖:
function debounce(fn, ms) { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; }节流:
function throttle(fn, ms) { let last = 0; return (...a) => { const now = Date.now(); if (now - last >= ms) { last = now; fn(...a); } }; } 查看答案即标记为已答