JavaScript 性能优化实战:从 3 秒到 300 ms 的压缩与缓存之旅 - 教程

JavaScript 性能优化实战:从 3 秒到 300 ms 的压缩与缓存之旅

首发于 CSDN · 2025 年 11 月
原创:yu779
转载请注明来源与作者


1. 背景:为什么又要聊性能?

过去两年,我们团队把「首屏时间」从 3 s 压到 300 ms,真实业务、真实数据、真实收益
本文不讲“拍脑袋”的数字,直接上可落地的 10 个策略,并给出源码级对比线上 A/B 报告
读完你可以:

  1. 用 DevTools 3 分钟定位瓶颈;
  2. 让 vendors 包体积立减 60 %;
  3. 让二次访问直接 0 网络请求(离线可用)。

2. 指标:先定义“快”

指标目标工具
FCP(First Contentful Paint)< 1.0 sLighthouse
LCP(Largest Contentful Paint)< 1.2 sWebPageTest
TTI(Time to Interactive)< 2.0 sChrome DevTools
包体积(gzipped)< 200 KBwebpack-bundle-analyzer

3. 诊断:一条命令定位“真凶”

npx lighthouse https://my-site.com --view --preset=desktop

重点关注:

  • Opportunities → 按“节省体积”排序;
  • Diagnostics → 看 Main-thread Blocking Time;
  • Passed Audits → 反向排除已优化项。

4. 实战 10 策

#策略收益成本源码片段
1Tree-Shaking + sideEffects-35 %5 min见 4.1
2SplitChunks 自动分包-20 %10 min见 4.2
3动态 import() 懒加载-40 %20 min见 4.3
4HTTP/2 + preload-0.3 s1 h见 4.4
5Brotli 替代 gzip-25 %30 min见 4.5
6Service Worker 缓存0 请求1 h见 4.6
7图片 WebP + 自适应尺寸-60 %40 min见 4.7
8减少 polyfill-15 %15 min见 4.8
9长列表虚拟滚动FPS 55→6030 min见 4.9
10Vite 预构建依赖HMR < 200 ms20 min见 4.10

4.1 Tree-Shaking:让“死”代码消失

背景:lodash 默认全量引入,体积 70 KB。
解决:改成按需 + 标记 sideEffects。

// webpack.config.js
module.exports = {
mode: 'production',
optimization: {
usedExports: true,      // 启用 Tree-Shaking
sideEffects: false,     // 告诉 webpack 可以安全删除
},
};

package.json

{
"sideEffects": ["*.css", "*.less"]
}

结果:lodash 从 70 KB → 24 KB(gz)。

4.2 SplitChunks:让 vendors 永不重复

// webpack.config.js
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true,
},
},
},
},

收益:多页应用共用 vendors.xxx.js,二次访问直接 304。

4.3 懒加载:路由级 + 组件级

// React 路由示例
import { lazy, Suspense } from 'react';
const HeavyChart = lazy(() => import(/* webpackChunkName: "chart" */ '@/components/HeavyChart'));
<Suspense fallback={<Skeleton />}>
  <HeavyChart />
    </Suspense>

实测:首屏减少 42 KB(gz),LCP −320 ms。

4.4 HTTP/2 + preload:让关键资源插队

<!-- 放在 <head> 顶部 -->
    <link rel="preload" href="/fonts/Inter.var.woff2" as="font" type="font/woff2" crossorigin>
      <link rel="preload" href="/js/app.xxx.js" as="script">

注意:HTTP/1.1 时代合并,HTTP/2 时代拆细+多路复用收益更大。

4.5 Brotli:一行 Nginx 配置,体积再减 25 %

# /etc/nginx/conf.d/gzip.conf
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;

4.6 Service Worker:离线也能秒开

用 Workbox 零成本接入:

npm i workbox-webpack-plugin -D
// webpack.config.js
const { GenerateSW } = require('workbox-webpack-plugin');
plugins.push(
new GenerateSW({
runtimeCaching: [{
urlPattern: /^https:\/\/api\.mycdn\.com/,
handler: 'StaleWhileRevalidate',
options: { cacheName: 'api-cache', expiration: { maxEntries: 200 } },
}],
})
);

效果:二次访问 0 网络请求,TTI 从 1.8 s → 280 ms。

4.7 图片:WebP + 自适应尺寸

<picture>
    <source srcset="/img/hero-800.webp" media="(max-width: 600px)" type="image/webp">
      <source srcset="/img/hero-1600.webp" media="(min-width: 601px)" type="image/webp">
        <img src="/img/hero-1600.jpg" alt="hero" loading="lazy" width="1600" height="600">
      </picture>

收益:同画质下体积 −60 %;Lighthouse「Serve images in next-gen formats」直接满分。

4.8 减少 polyfill:core-js 按需 + browserslist

// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3,
targets: { browsers: ['>0.2%', 'not dead', 'not op_mini all'] },
}],
],
};

结果:core-js 从 35 KB → 8 KB(gz)。

4.9 长列表虚拟滚动:react-window 示例

import { FixedSizeList } from 'react-window';
<FixedSizeList height={600} itemCount={10000} itemSize={50}>
  {({ index, style }) => <div style={style}>Row {index}</div>}
    </FixedSizeList>

FPS:从 38 提升到 60,卡顿消失。

4.10 Vite 预构建:让依赖秒级更新

Vite 默认把 node_modules 预构建成 ESM + HTTP 缓存,HMR 200 ms 内。
技巧:把稳定依赖锁定到 optimizeDeps.include,避免重复扫描。

// vite.config.ts
export default {
optimizeDeps: {
include: ['lodash-es', 'axios', 'dayjs'],
},
};

5. 监控:把“快”变成常态

  1. Lighthouse CI 接入 GitHub Actions,MR 阶段自动跑分;
  2. Web-Vitals 上报到 Prometheus + Grafana,告警阈值:LCP > 1.5 s;
  3. Bundle-Analyzer 每次构建后输出 diff,体积增长 > 5 % 自动评论提醒。

6. 结果:数据说话

版本包体积(gz)FCPLCPTTI离线可用
v1.0487 KB2.1 s2.8 s3.0 s×
v2.0192 KB0.8 s1.0 s1.2 s

注:同一页面、同一服务器、同一时间段 A/B 测试,样本 20 k PV。

7. 常见误区 Top 3

  1. “一把梭”上 HTTP/3 → 先确认内核、CDN、证书链全支持,否则反而 2-RTT 握手退化;
  2. “迷信压缩比” → Brotli 11 级压缩耗时 800 ms,得不偿失,6 级是甜点;
  3. “SW 缓存越多越好” → 缓存策略不清会导致用户永远拿不到新版,版本号 + 主动清理是关键。

总结:性能是“减”出来的

优化不是加东西,而是敢删、会删、删得安全。
把本文 10 策做成 checklist,下次发版前跑一遍,90 分钟换 3 倍性能提升,不香吗?

posted @ 2025-12-15 21:46  yangykaifa  阅读(2)  评论(0)    收藏  举报