一、前置认知:性能优化的核心价值与衡量标准
经过前十四篇的学习,我们已具备从项目架构设计到多端落地的全流程能力,但在"秒杀活动峰值10万并发""电商首页日均千万级访问"等职场高并发场景中,仅靠架构合理无法保障用户体验------页面加载慢、交互卡顿、高峰期白屏等问题,会直接导致用户流失。据亚马逊官方数据显示:页面加载时间每延迟1秒,转化率会下降7%;谷歌数据则表明,移动端页面加载时间超过3秒,53%的用户会直接关闭页面。
前端性能优化的核心目标是在合理研发成本下,通过"加载优化、渲染优化、运行时优化"三大维度,实现"快加载、稳运行、好交互"的用户体验,同时降低服务器带宽和资源消耗。这是前端工程师应对高并发场景的核心竞争力,也是大型互联网企业面试的高频重点。
职场关键认知:性能优化不是"单点调优",而是"全链路系统工程"。需覆盖"资源构建→CDN分发→浏览器加载→页面渲染→用户交互"全流程,同时结合业务场景权衡优化优先级(如秒杀场景优先保障加载速度和并发稳定性,后台管理系统优先保障交互流畅性)。
二、Day43:性能指标体系------从"凭感觉"到"数据驱动"
性能优化的前提是建立科学的指标体系,明确"优化什么、如何衡量、目标是多少"。避免陷入"优化后感觉变快了"的主观判断,需通过量化指标评估优化效果。前端性能指标可分为"加载性能""渲染性能""运行时性能"三大类,覆盖用户从打开页面到交互的全流程。
1. 核心性能指标定义与标准
基于Web Vitals(谷歌提出的核心用户体验指标)和行业通用标准,梳理职场必备的6大核心指标,不同业务场景目标值不同,需结合实际需求制定:
| 指标类型 | 核心指标 | 指标定义 | 用户体验含义 | 行业优秀标准(高并发场景) |
|---|---|---|---|---|
| 加载性能 | LCP(最大内容绘制) | 页面加载过程中,最大的可见内容元素绘制完成的时间 | 用户感知"页面是否开始加载"的核心指标 | ≤2.5秒(秒杀页≤1.5秒) |
| 加载性能 | FID(首次输入延迟) | 用户首次与页面交互(点击、输入等)到浏览器响应的时间 | 用户感知"页面是否可交互"的核心指标 | ≤100毫秒(支付页≤50毫秒) |
| 加载性能 | TTI(可交互时间) | 页面完全加载并能稳定响应用户交互的时间 | 页面整体"可用"的标志 | ≤3.5秒(后台系统≤5秒) |
| 渲染性能 | FCP(首次内容绘制) | 页面首次绘制出文本、图片等可见内容的时间 | 用户感知"页面是否有反馈"的初始指标 | ≤1.8秒(营销页≤1秒) |
| 渲染性能 | CLS(累积布局偏移) | 页面加载过程中,元素意外偏移的累积分数 | 用户感知"页面是否稳定"的关键指标(避免点击错位) | ≤0.1(商品详情页≤0.05) |
| 运行时性能 | FPS(每秒帧率) | 浏览器每秒绘制页面的次数,正常为60FPS(每帧约16.7毫秒) | 用户感知"交互是否流畅"的核心指标(如滚动、动画) | ≥50FPS(动画场景≥55FPS) |
2. 指标监测工具实战
掌握工具是获取性能数据的基础,职场中常用"开发环境调试工具"和"线上环境监控工具"两类,覆盖优化全流程:
实战1:开发环境调试(Chrome DevTools核心功能)
开发阶段通过Chrome开发者工具定位性能瓶颈,重点使用"Performance""Lighthouse""Network"面板:
-
Performance面板:定位渲染和运行时瓶颈
-
操作步骤:打开面板→点击"录制"按钮→操作页面(如滚动、点击)→停止录制→分析结果;
-
核心分析点:
-
FPS图表:低于50的区域表示卡顿,需查看对应时间段的"Main"线程任务(如长任务阻塞);
-
Main线程:红色任务表示长任务(超过50毫秒),需拆分(如大型列表渲染、复杂计算);
-
示例:录制商品列表滚动过程,发现FPS骤降至30,对应Main线程有"渲染列表"长任务,需优化为虚拟滚动。
-
-
-
Lighthouse面板:全面性能评估
-
操作步骤:打开面板→选择"性能""最佳实践"等评估项→点击"生成报告";
-
核心价值:自动生成性能评分(0-100),并给出具体优化建议(如"启用文本压缩""移除未使用的JS");
-
职场用法:优化前后各生成一次报告,通过评分变化和建议完成度评估优化效果。
-
-
Network面板:分析加载瓶颈
-
操作步骤:打开面板→勾选"Disable cache"→刷新页面→查看资源加载详情;
-
核心分析点:
-
资源大小:大于100KB的JS/CSS需拆分或压缩,大于50KB的图片需优化格式;
-
加载顺序:关键资源(如首屏CSS、核心JS)应优先加载,非关键资源(如底部广告JS)应延迟加载;
-
waterfall图:查看是否有资源加载阻塞(如CSS阻塞JS执行,需调整加载方式)。
-
-
实战2:线上环境监控(企业级方案)
开发环境无法模拟真实用户的网络和设备差异,需通过线上监控工具获取真实性能数据。职场中常用"自建监控平台"和"第三方工具"结合的方案:
# 1. 核心监控指标上报(自建监控核心代码) // 监控LCP(最大内容绘制) new PerformanceObserver((entryList) => { const entries = entryList.getEntries(); const lcpEntry = entries[entries.length - 1]; // 最后一个entry为最大内容 const lcpTime = lcpEntry.startTime; // LCP时间(毫秒) // 上报数据(对接后端接口,携带用户设备、网络等信息) reportPerformance({ indicator: 'LCP', value: lcpTime, device: navigator.userAgent, network: navigator.connection.effectiveType, // 网络类型(4g/5g/wifi) page: window.location.pathname }); }).observe({ type: 'largest-contentful-paint', buffered: true }); // 监控FID(首次输入延迟) new PerformanceObserver((entryList) => { const entry = entryList.getEntries()[0]; const fidTime = entry.processingStart - entry.startTime; // FID时间 reportPerformance({ indicator: 'FID', value: fidTime, ...otherInfo }); }).observe({ type: 'first-input', buffered: true }); // 监控CLS(累积布局偏移) let clsScore = 0; new PerformanceObserver((entryList) => { entryList.getEntries().forEach(entry => { if (!entry.hadRecentInput) { // 排除用户交互导致的偏移(如点击按钮) clsScore += entry.value; // 实时上报累积分数 reportPerformance({ indicator: 'CLS', value: clsScore, ...otherInfo }); } }); }).observe({ type: 'layout-shift', buffered: true }); // 2. 错误监控(JS错误和资源加载错误) // 监控JS错误 window.addEventListener('error', (err) => { reportError({ type: 'js_error', message: err.message, stack: err.error?.stack, url: err.filename, line: err.lineno }); }); // 监控资源加载错误(如图片、CSS加载失败) window.addEventListener('error', (err) => { if (err.target.tagName) { // 资源加载错误会有tagName reportError({ type: 'resource_error', resourceType: err.target.tagName.toLowerCase(), resourceUrl: err.target.src || err.target.href, message: err.message }); } }, true); // 第三个参数为true,捕获阶段监听 // 3. 职场注意事项: // - 采样上报:高并发场景下,为避免服务器压力,按10%-20%比例采样上报; // - 延迟上报:页面卸载时通过navigator.sendBeacon()上报,确保数据不丢失; // - 维度分析:按"页面、设备、网络、地区"等维度统计,定位特定场景的性能问题。
第三方工具推荐:中小型项目可直接使用第三方工具降低开发成本,如阿里云ARMS、腾讯前端监控平台、Sentry(错误监控专用),这些工具已封装好指标采集和可视化分析功能,支持一键查看各维度性能数据。
三、Day44:全链路性能优化实战------从"构建"到"渲染"
基于指标体系,从"资源构建→CDN分发→浏览器加载→页面渲染"全链路展开优化,每个环节对应不同的优化策略,需结合业务场景选择优先级:
1. 资源构建优化:减小资源体积(前端工程化延伸)
资源体积直接影响加载速度,通过构建工具优化资源,是性能优化的基础环节。基于Webpack/Vite的核心优化策略:
实战3:代码压缩与Tree-Shaking
# 1. Webpack配置优化(vue.config.js或webpack.config.js) const { defineConfig } = require('@vue/cli-service'); const TerserPlugin = require('terser-webpack-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); module.exports = defineConfig({ configureWebpack: { optimization: { // 1. JS压缩:移除console、debugger,开启多线程压缩 minimizer: [ new TerserPlugin({ terserOptions: { compress: { drop_console: process.env.NODE_ENV === 'production', // 生产环境移除console drop_debugger: true, pure_funcs: ['console.log'] // 彻底移除console.log } }, parallel: true // 多线程压缩(速度提升50%+) }), new CssMinimizerPlugin() // CSS压缩(默认未开启) ], // 2. Tree-Shaking:移除未使用的代码(仅生产环境生效) usedExports: true, // 3. 代码分割:拆分公共依赖(避免重复加载) splitChunks: { chunks: 'all', // 对所有类型的chunk进行分割(同步+异步) cacheGroups: { // 拆分第三方依赖(如vue、pinia、axios) vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: 10, // 优先级高于common minSize: 0 // 即使体积小也拆分(便于缓存) }, // 拆分公共业务代码(如多个页面共用的工具函数) common: { name: 'common', priority: 5, minSize: 30 * 1024, // 体积大于30KB才拆分 minChunks: 2 // 被至少2个页面引用才拆分 } } } }, // 4. 关闭生产环境sourceMap(减小资源体积,避免代码泄露) devtool: process.env.NODE_ENV === 'production' ? false : 'source-map' }, // 5. Vue CLI专属:图片压缩(需安装image-webpack-loader) chainWebpack: (config) => { config.module .rule('images') .use('image-webpack-loader') .loader('image-webpack-loader') .options({ mozjpeg: { quality: 80, progressive: true }, // JPG压缩 optipng: { enabled: false }, // PNG压缩(可根据需求开启) pngquant: { quality: [0.6, 0.8] }, // PNG压缩 gifsicle: { interlaced: false } // GIF压缩 }) .end(); } }); # 2. Vite配置优化(vite.config.js) // Vite默认已开启Tree-Shaking和JS/CSS压缩,需补充图片优化和代码分割 import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import viteCompression from 'vite-plugin-compression'; // 开启gzip压缩 export default defineConfig({ plugins: [ vue(), // 开启gzip压缩(配合服务器启用,体积减小60%+) viteCompression({ algorithm: 'gzip', threshold: 10240, // 大于10KB的文件才压缩 deleteOriginFile: false // 不删除原文件 }) ], build: { // 代码分割:拆分公共依赖 rollupOptions: { output: { manualChunks: { vendor: ['vue', 'pinia', 'axios'], common: ['@/utils/format.js', '@/components/common/Button.vue'] } }, // 图片优化:指定输出格式和质量 assetsInlineLimit: 4096, // 小于4KB的图片转为base64 assetFileNames: { images: 'assets/img/[name].[hash:8].[ext]' } }, // 关闭生产环境sourceMap sourcemap: false } });
关键效果:通过上述配置,JS/CSS体积可减小30%-60%,图片体积可减小20%-50%,显著降低加载时间。
2. 加载策略优化:提升资源加载效率
在资源体积优化的基础上,通过合理的加载策略让"关键资源优先加载",非关键资源延迟加载,最大化利用浏览器加载能力:
实战4:关键资源预加载与非关键资源延迟加载
<!-- 1. HTML头部关键资源优化:优先加载首屏CSS和核心JS --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>商品详情页</title> <!-- 首屏CSS内联:避免额外网络请求(体积控制在10KB内) --> <style> .product-detail { width: 100%; padding: 10px; } .product-img { width: 100%; height: auto; } /* 仅包含首屏必要样式 */ </style> <!-- 非首屏CSS延迟加载:使用media="print"让浏览器不阻塞渲染 --> <link rel="stylesheet" href="/css/non-critical.css" media="print" onload="this.media='all'"> <!-- 预加载关键字体:避免字体闪烁(FOIT) --> <link rel="preload" href="/fonts/iconfont.woff2" as="font" type="font/woff2" crossorigin> <!-- 预连接CDN域名:提前建立TCP连接,减少后续请求延迟 --> <link rel="preconnect" href="https://cdn.example.com"> </head> <body> <div class="product-detail"> <img class="product-img" src="/img/product-cover.jpg" alt="商品封面"> <!-- 首屏内容 --> </div> <!-- 2. 非关键JS延迟加载:使用defer/async或动态导入 --> <!-- 核心JS:同步加载(如状态管理、路由) --> <script src="/js/core.js"></script> <!-- 非核心JS:defer加载(如统计、广告,不阻塞DOM解析) --> <script src="/js/statistics.js" defer></script> <!-- 按需加载JS:滚动到指定位置再加载(如评论模块) --> <div id="comment-container"></div> <script> // 监听滚动事件,按需加载评论模块 const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { // 动态导入评论模块JS import('./js/comment.js').then((module) => { module.initComment(); // 初始化评论模块 }); observer.unobserve(entries[0].target); // 停止监听 } }); observer.observe(document.getElementById('comment-container')); </script> <!-- 3. 图片加载优化:懒加载+响应式图片 --> <!-- 普通图片懒加载:使用native lazyload(现代浏览器支持) --> <img src="/img/product-1.jpg" alt="商品图片1" loading="lazy"> <!-- 响应式图片:根据屏幕分辨率加载不同尺寸图片 --> <picture> <source srcset="/img/product-2-large.jpg" media="(min-width: 1024px)"> <source srcset="/img/product-2-middle.jpg" media="(min-width: 768px)"> <img src="/img/product-2-small.jpg" alt="商品图片2" loading="lazy"> </picture> </body> </html>
核心原理:通过"内联关键资源减少请求数""预加载提前获取关键资源""延迟加载非关键资源",让首屏加载时间缩短40%+,同时避免资源加载阻塞渲染。
3. 渲染与运行时优化:保障交互流畅
加载完成后,渲染和运行时性能直接影响用户交互体验,重点解决"布局偏移、长任务阻塞、动画卡顿"等问题:
实战5:渲染优化与长任务拆分
<!-- 1. 避免布局偏移(优化CLS):给图片和动态元素设置固定占位 --> <template> <div class="product-card"> <!-- 图片占位:通过padding-top实现固定宽高比(避免加载后偏移) --> <div class="img-container"> <img src="product.jpg" alt="商品图片" loading="lazy"> </div> <h3 class="product-title">{``{ product.name }}</h3> <!-- 动态内容占位:使用骨架屏,避免内容加载后偏移 --> <Skeleton v-if="loading" /> <div class="product-price" v-else>{``{ product.price }}</div> </div> </template> <style scoped> /* 图片容器:固定宽高比1:1,避免加载后布局偏移 */ .img-container { position: relative; width: 100%; padding-top: 100%; /* 宽高比1:1 */ overflow: hidden; } .img-container img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } </style>
# 2. 拆分长任务(优化FID和FPS):将超过50ms的任务拆分为微任务 // 问题代码:渲染1000条商品列表,导致主线程阻塞200ms,FPS骤降 function renderProductList(products) { const container = document.getElementById('product-container'); products.forEach(product => { const item = document.createElement('div'); item.className = 'product-item'; item.innerHTML = ` ${product.name}${product.price} `; container.appendChild(item); }); } // 优化后:使用requestIdleCallback或分批次渲染 function renderProductListOptimized(products) { const container = document.getElementById('product-container'); const batchSize = 50; // 每批渲染50条(控制每批耗时≤16ms) let currentIndex = 0; // 分批次渲染函数 function renderBatch() { const endIndex = Math.min(currentIndex + batchSize, products.length); for (let i = currentIndex; i < endIndex; i++) { const product = products[i]; const item = document.createElement('div'); item.className = 'product-item'; item.innerHTML = ` ${product.name}${product.price} `; container.appendChild(item); } currentIndex = endIndex; // 未渲染完成,继续下一批 if (currentIndex < products.length) { requestAnimationFrame(renderBatch); // 配合浏览器重绘周期 } } // 启动分批次渲染 renderBatch(); } # 3. 动画优化:使用CSS动画替代JS动画,避免重排重绘 // 问题:JS动画修改width/height,触发频繁重排重绘(FPS低) function animateBox() { const box = document.getElementById('box'); let left = 0; setInterval(() => { box.style.left = `${left++}px`; }, 16); } // 优化:CSS动画使用transform(仅触发合成层,不重排重绘) // CSS部分 // .box { // transition: transform 0.3s ease; // } // .box.active { // transform: translateX(300px); // } // JS部分(仅控制类名切换) function animateBoxOptimized() { const box = document.getElementById('box'); box.classList.add('active'); } # 4. Vue项目额外优化:避免不必要的响应式和重渲染 // 1. 非响应式数据使用markRaw(如静态配置数据) import { markRaw, reactive } from 'vue'; const state = reactive({ // 静态商品分类数据,无需响应式 categories: markRaw([ { id: 1, name: '电子产品' }, { id: 2, name: '服装' } ]) }); // 2. 使用v-memo缓存组件(避免频繁重渲染) <template> <ProductItem v-for="item in productList" :key="item.id" :product="item" v-memo="[item.id, item.price]" // 仅当id或price变化时才重渲染 /> </template>
四、Day45:高并发场景专项优化------秒杀系统实战
秒杀是职场中典型的高并发场景(如双11秒杀、限量商品抢购),面临"瞬间千万级请求、页面卡顿、接口超时"等问题,需结合"前端优化+后端配合"实现稳定运行。以下是秒杀系统前端专项优化方案:
1. 秒杀场景核心痛点与优化目标
-
核心痛点:
-
请求峰值高:秒杀开始瞬间,用户集中点击"抢购"按钮,导致前端请求频繁、后端接口压垮;
-
页面卡顿:大量请求触发JS线程阻塞,同时倒计时动画、库存实时更新等导致渲染压力大;
-
数据一致性:前端库存显示与后端实际库存不一致,导致用户误操作。
-
-
优化目标:
-
前端请求限流:同一用户每秒最多发起1次抢购请求,减少无效请求;
-
页面加载速度:秒杀页LCP≤1.5秒,TTI≤2秒;
-
交互稳定性:倒计时动画流畅(≥55FPS),库存更新无卡顿,按钮点击响应≤50ms。
-
2. 秒杀系统前端全链路优化实战
实战6:秒杀页资源加载优化(极致减小加载时间)
<!-- 1. 秒杀页极简HTML结构(减少DOM节点) --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>限时秒杀</title> <!-- 1. 关键CSS内联(仅包含秒杀页必要样式,体积≤5KB) --> <style> * { margin: 0; padding: 0; box-sizing: border-box; } .seckill-container { max-width: 1200px; margin: 0 auto; padding: 10px; } .seckill-card { border: 1px solid #f00; border-radius: 4px; padding: 10px; margin-bottom: 10px; } .seckill-countdown { color: #f00; font-size: 18px; margin: 10px 0; } .seckill-btn { width: 100%; height: 40px; background: #f00; color: #fff; border: none; border-radius: 4px; } .seckill-btn:disabled { background: #ccc; } .stock { color: #666; margin: 10px 0; } </style> <!-- 2. 预连接CDN和后端接口域名 --> <link rel="preconnect" href="https://cdn.seckill.example.com"> <link rel="preconnect" href="https://api.seckill.example.com"> <!-- 3. 预加载核心JS(秒杀逻辑JS) --> <link rel="preload" href="/js/seckill-core.js" as="script"> </head> <body> <div class="seckill-container"> <div class="seckill-card"> <img src="https://cdn.seckill.example.com/img/seckill-product.jpg" alt="秒杀商品" loading="eager"> <h3>秒杀商品名称</h3> <p class="seckill-countdown" id="countdown">00:00:00</p> <p class="stock" id="stock">库存:100件</p> <button class="seckill-btn" id="seckillBtn" disabled>秒杀未开始</button> </div> </div> <!-- 4. 核心JS同步加载(极简逻辑,体积≤10KB) --> <script src="/js/seckill-core.js"></script> <!-- 5. 统计等非核心JS延迟加载 --> <script src="/js/seckill-stat.js" defer></script> </body> </html>
实战7:秒杀交互与请求优化(减少无效请求)
// seckill-core.js 核心逻辑(极简实现) document.addEventListener('DOMContentLoaded', () => { const countdownEl = document.getElementById('countdown'); const stockEl = document.getElementById('stock'); const seckillBtn = document.getElementById('seckillBtn'); const seckillId = 'seckill123'; // 秒杀活动ID const userId = localStorage.getItem('userId'); // 用户ID(登录后获取) // 1. 倒计时优化:使用requestAnimationFrame,避免setInterval漂移 let endTime = 1735689600000; // 秒杀结束时间(后端返回,前端仅做展示) function updateCountdown() { const now = Date.now(); if (now >= endTime) { countdownEl.textContent = '秒杀已结束'; seckillBtn.disabled = true; seckillBtn.textContent = '秒杀已结束'; return; } const diff = endTime - now; const hours = Math.floor(diff / 3600000).toString().padStart(2, '0'); const minutes = Math.floor((diff % 3600000) / 60000).toString().padStart(2, '0'); const seconds = Math.floor((diff % 60000) / 1000).toString().padStart(2, '0'); countdownEl.textContent = `${hours}:${minutes}:${seconds}`; requestAnimationFrame(updateCountdown); } // 2. 前端请求限流:同一用户3秒内仅能发起1次抢购请求 let isRequesting = false; function seckillRequest() { if (isRequesting) return Promise.reject('请求过于频繁,请稍后再试'); isRequesting = true; // 3秒后重置请求状态(即使请求失败也释放) setTimeout(() => { isRequesting = false; }, 3000); // 发起抢购请求(使用fetch,配合AbortController可取消) const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒超时 return fetch(`https://api.seckill.example.com/seckill/${seckillId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify({ userId }), signal: controller.signal, credentials: 'include' }) .then(res => { clearTimeout(timeoutId); if (!res.ok) throw new Error('请求失败'); return res.json(); }) .finally(() => { clearTimeout(timeoutId); // 可根据后端响应结果调整重置时间,避免恶意请求 }); } // 3. 按钮点击优化:防止重复点击,添加交互反馈 seckillBtn.addEventListener('click', async () => { seckillBtn.disabled = true; seckillBtn.textContent = '抢购中...'; try { const res = await seckillRequest(); if (res.success) { // 抢购成功:跳转订单页 window.location.href = `/order/create?orderId=${res.orderId}`; } else { // 抢购失败:根据错误类型提示 if (res.code === 1001) { alert('库存不足'); stockEl.textContent = '库存:0件'; } else if (res.code === 1002) { alert('您已参与过本次秒杀'); } else { alert('抢购失败,请稍后再试'); seckillBtn.disabled = false; seckillBtn.textContent = '立即抢购'; } } } catch (err) { alert('网络异常,请稍后再试'); seckillBtn.disabled = false; seckillBtn.textContent = '立即抢购'; } }); // 4. 库存更新:通过WebSocket实时获取库存(避免轮询) function initStockWebSocket() { if (!window.WebSocket) return; // 降级处理:轮询 const ws = new WebSocket(`wss://api.seckill.example.com/stock/${seckillId}`); ws.onopen = () => console.log('库存WebSocket连接成功'); ws.onmessage = (e) => { const data = JSON.parse(e.data); stockEl.textContent = `库存:${data.stock}件`; // 库存为0时禁用按钮 if (data.stock <= 0) { seckillBtn.disabled = true; seckillBtn.textContent = '已抢完'; } }; ws.onclose = () => { // 重连机制:3秒后重连 setTimeout(initStockWebSocket, 3000); }; } // 5. 初始化流程 function init() { // 从后端获取秒杀信息(如结束时间、初始库存) fetch(`https://api.seckill.example.com/info/${seckillId}`) .then(res => res.json()) .then(data => { endTime = data.endTime; stockEl.textContent = `库存:${data.stock}件`; // 秒杀未开始时禁用按钮,开始后启用 if (Date.now() < data.startTime) { seckillBtn.disabled = true; seckillBtn.textContent = '秒杀未开始'; // 监听秒杀开始时间 setTimeout(() => { seckillBtn.disabled = false; seckillBtn.textContent = '立即抢购'; }, data.startTime - Date.now()); } else if (Date.now() > data.endTime) { seckillBtn.disabled = true; seckillBtn.textContent = '秒杀已结束'; } else { seckillBtn.disabled = false; seckillBtn.textContent = '立即抢购'; } // 启动倒计时和WebSocket updateCountdown(); initStockWebSocket(); }); } // 启动初始化 init(); });
实战8:秒杀系统后端配合要点(前端需了解)
-
接口限流:后端对秒杀接口按"用户ID+IP"限流,避免单用户高频请求;
-
缓存预热:秒杀开始前,将商品信息和库存缓存到Redis,减少数据库压力;
-
队列削峰:使用消息队列(如RabbitMQ)接收抢购请求,异步处理订单创建,避免接口超时;
-
降级策略:高峰期关闭非核心功能(如商品评价、分享),优先保障秒杀流程。
五、3天总结:前端性能优化职场能力清单
-
指标体系能力:掌握LCP、FID、CLS等核心指标的定义和标准,能使用Chrome DevTools和线上监控工具获取和分析性能数据;
-
全链路优化能力:能从"构建、加载、渲染、运行时"全链路制定优化策略,如代码压缩、按需加载、分批次渲染;
-
高并发场景能力:掌握秒杀等高并发场景的前端优化方案,包括请求限流、WebSocket实时更新、极简资源加载;
-
工具使用能力:熟练使用Webpack/Vite进行构建优化,使用Chrome DevTools定位性能瓶颈,使用监控工具实现数据驱动优化;
-
业务权衡能力:能结合业务场景选择优化优先级(如营销页优先加载速度,后台系统优先交互流畅性),避免过度优化;
-
作业:基于之前的电商项目,完成以下任务:① 对商品列表页进行全链路优化,使用Lighthouse评估优化前后的评分变化;② 实现一个简易秒杀页面,包含倒计时、请求限流、库存实时更新功能;③ 搭建基础的性能监控脚本,实现LCP、FID、错误信息的上报。