当用户访问你的网站时,如果页面加载时间超过3秒,跳出率会飙升至40%以上。更糟糕的是,移动端用户的耐心只有2秒。这意味着性能优化不仅仅是技术问题,更直接关系到业务成果。
经过多年的前端开发实践,我发现很多开发者在性能优化时存在一个误区:过分关注工具和框架的选择,却忽略了最基础但最关键的优化策略。今天我们就来深入剖析前端性能优化的核心要点。
在开始优化之前,我们需要明确衡量标准。Google 提出的 Core Web Vitals 为我们提供了科学的评估体系:
LCP (Largest Contentful Paint)
FID (First Input Delay)
CLS (Cumulative Layout Shift)
// 性能监控代码示例
class PerformanceMonitor {
constructor() {
this.metrics = {};
this.observer = null;
this.initObserver();
}
initObserver() {
// 监控 LCP
this.observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
if (entry.entryType === 'largest-contentful-paint') {
this.metrics.lcp = entry.startTime;
this.reportMetric('LCP', entry.startTime);
}
});
});
this.observer.observe({ entryTypes: ['largest-contentful-paint'] });
// 监控 FID
this.observeFID();
// 监控 CLS
this.observeCLS();
}
observeFID() {
new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
if (entry.entryType === 'first-input') {
const fid = entry.processingStart - entry.startTime;
this.metrics.fid = fid;
this.reportMetric('FID', fid);
}
});
}).observe({ entryTypes: ['first-input'] });
}
observeCLS() {
let clsValue = 0;
new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
if (!entry.hadRecentInput) {
clsValue += entry.value;
}
});
this.metrics.cls = clsValue;
this.reportMetric('CLS', clsValue);
}).observe({ entryTypes: ['layout-shift'] });
}
reportMetric(name, value) {
// 发送性能数据到分析平台
fetch('/api/performance', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ metric: name, value, timestamp: Date.now() })
}).catch(err => console.error('性能数据上报失败:', err));
}
}
// 初始化性能监控
const monitor = new PerformanceMonitor();
1. 减少主线程阻塞
JavaScript 是单线程的,长时间运行的任务会阻塞用户交互。我们需要将耗时任务拆分:
// 问题代码:大量计算阻塞主线程
function processLargeDataset(data) {
const result = [];
for (let i = 0; i < data.length; i++) {
// 复杂计算
result.push(complexCalculation(data[i]));
}
return result;
}
// 优化方案:时间切片处理
class TaskScheduler {
constructor() {
this.tasks = [];
this.isRunning = false;
}
addTask(task) {
this.tasks.push(task);
if (!this.isRunning) {
this.runTasks();
}
}
runTasks() {
this.isRunning = true;
const runChunk = () => {
const start = performance.now();
// 在5ms时间片内执行任务
while (this.tasks.length > 0 && performance.now() - start < 5) {
const task = this.tasks.shift();
task();
}
if (this.tasks.length > 0) {
// 让出控制权给浏览器
requestIdleCallback(runChunk);
} else {
this.isRunning = false;
}
};
requestIdleCallback(runChunk);
}
}
// 使用示例
function processLargeDatasetOptimized(data) {
const result = [];
const scheduler = new TaskScheduler();
return new Promise((resolve) => {
let index = 0;
const processChunk = () => {
if (index < data.length) {
scheduler.addTask(() => {
result.push(complexCalculation(data[index]));
index++;
processChunk();
});
} else {
resolve(result);
}
};
processChunk();
});
}
2. 内存优化与垃圾回收
内存泄漏是性能杀手,特别是在单页应用中:
// 内存泄漏的常见场景和解决方案
class ComponentManager {
constructor() {
this.components = new Map();
this.observers = new WeakMap(); // 使用 WeakMap 避免内存泄漏
this.timers = new Set();
}
createComponent(id, config) {
const component = {
id,
config,
cleanup: () => {
// 清理事件监听器
this.removeEventListeners(component);
// 清理定时器
this.clearTimers(component);
// 清理 DOM 引用
this.clearDOMReferences(component);
}
};
this.components.set(id, component);
return component;
}
removeComponent(id) {
const component = this.components.get(id);
if (component) {
// 执行清理函数
component.cleanup();
this.components.delete(id);
}
}
// 安全的定时器管理
setTimeout(callback, delay, componentId) {
const timerId = setTimeout(() => {
callback();
this.timers.delete(timerId);
}, delay);
this.timers.add(timerId);
return timerId;
}
clearTimers(component) {
this.timers.forEach(timerId => {
clearTimeout(timerId);
this.timers.delete(timerId);
});
}
// 对象池模式减少垃圾回收
createObjectPool(createFn, resetFn, initialSize = 10) {
const pool = [];
// 预创建对象
for (let i = 0; i < initialSize; i++) {
pool.push(createFn());
}
return {
get() {
return pool.length > 0 ? pool.pop() : createFn();
},
release(obj) {
resetFn(obj);
pool.push(obj);
}
};
}
}
1. 减少重绘和回流
CSS 的变化会触发重绘或回流,影响渲染性能:
/* 避免频繁的布局变化 */
.animation-optimized {
/* 使用 transform 和 opacity,只触发合成层 */
transform: translateX(0);
opacity: 1;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.animation-optimized:hover {
/* 只改变 transform,不触发回流 */
transform: translateX(10px);
}
/* 避免的写法 - 会触发回流 */
.animation-bad {
left: 0;
transition: left 0.3s ease;
}
.animation-bad:hover {
left: 10px; /* 改变位置属性会触发回流 */
}
// JavaScript 中的性能优化
class DOMOptimizer {
constructor() {
this.batchedUpdates = [];
this.updateScheduled = false;
}
// 批量DOM更新
batchUpdate(updateFn) {
this.batchedUpdates.push(updateFn);
if (!this.updateScheduled) {
this.updateScheduled = true;
requestAnimationFrame(() => {
// 批量执行所有更新
this.batchedUpdates.forEach(update => update());
this.batchedUpdates = [];
this.updateScheduled = false;
});
}
}
// 虚拟滚动实现
createVirtualScroller(container, items, itemHeight) {
const visibleCount = Math.ceil(container.clientHeight / itemHeight);
const bufferCount = 5; // 缓冲区大小
let scrollTop = 0;
let startIndex = 0;
let endIndex = visibleCount + bufferCount;
const updateVisibleItems = () => {
const newStartIndex = Math.floor(scrollTop / itemHeight);
const newEndIndex = Math.min(
newStartIndex + visibleCount + bufferCount,
items.length
);
if (newStartIndex !== startIndex || newEndIndex !== endIndex) {
startIndex = newStartIndex;
endIndex = newEndIndex;
this.renderVisibleItems(container, items, startIndex, endIndex, itemHeight);
}
};
container.addEventListener('scroll', (e) => {
scrollTop = e.target.scrollTop;
this.batchUpdate(updateVisibleItems);
});
// 初始渲染
updateVisibleItems();
}
renderVisibleItems(container, items, startIndex, endIndex, itemHeight) {
const fragment = document.createDocumentFragment();
// 清空容器
container.innerHTML = '';
// 添加顶部占位符
const topSpacer = document.createElement('div');
topSpacer.style.height = `${startIndex * itemHeight}px`;
fragment.appendChild(topSpacer);
// 渲染可见项
for (let i = startIndex; i < endIndex; i++) {
const item = this.createItemElement(items[i], itemHeight);
fragment.appendChild(item);
}
// 添加底部占位符
const bottomSpacer = document.createElement('div');
bottomSpacer.style.height = `${(items.length - endIndex) * itemHeight}px`;
fragment.appendChild(bottomSpacer);
container.appendChild(fragment);
}
}
图片通常占据网页资源的60-70%,优化图片是提升性能的关键:
// 智能图片加载管理器
class ImageOptimizer {
constructor() {
this.lazyImages = new Set();
this.observer = null;
this.initIntersectionObserver();
}
initIntersectionObserver() {
this.observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadImage(entry.target);
this.observer.unobserve(entry.target);
}
});
}, {
rootMargin: '50px' // 提前50px开始加载
});
}
// 响应式图片加载
loadImage(img) {
const src = this.getOptimalImageSrc(img);
// 使用 WebP 格式(如果支持)
if (this.supportsWebP()) {
const webpSrc = src.replace(/\.(jpg|jpeg|png)$/, '.webp');
this.loadWithFallback(img, webpSrc, src);
} else {
img.src = src;
}
}
getOptimalImageSrc(img) {
const devicePixelRatio = window.devicePixelRatio || 1;
const containerWidth = img.parentElement.clientWidth;
const optimalWidth = Math.ceil(containerWidth * devicePixelRatio);
// 根据屏幕尺寸选择合适的图片
const baseSrc = img.dataset.src;
return `${baseSrc}?w=${optimalWidth}&q=85&f=auto`;
}
loadWithFallback(img, primarySrc, fallbackSrc) {
const testImg = new Image();
testImg.onload = () => {
img.src = primarySrc;
img.classList.add('loaded');
};
testImg.onerror = () => {
img.src = fallbackSrc;
img.classList.add('loaded');
};
testImg.src = primarySrc;
}
supportsWebP() {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
return canvas.toDataURL('image/webp').startsWith('data:image/webp');
}
// 图片预加载
preloadCriticalImages(imageSrcs) {
const promises = imageSrcs.map(src => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = resolve;
img.onerror = reject;
img.src = src;
});
});
return Promise.allSettled(promises);
}
// 注册懒加载图片
registerLazyImage(img) {
this.lazyImages.add(img);
this.observer.observe(img);
}
}
// 使用示例
const imageOptimizer = new ImageOptimizer();
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
// 预加载关键图片
const criticalImages = [
'/images/hero-banner.webp',
'/images/logo.webp'
];
imageOptimizer.preloadCriticalImages(criticalImages);
// 注册懒加载图片
document.querySelectorAll('img[data-src]').forEach(img => {
imageOptimizer.registerLazyImage(img);
});
});
现代前端应用往往包含大量代码,合理的代码分割能显著提升首屏加载速度:
// 路由级别的代码分割
class RouteManager {
constructor() {
this.routes = new Map();
this.loadedChunks = new Set();
this.loadingPromises = new Map();
}
// 注册路由
registerRoute(path, importFn) {
this.routes.set(path, {
import: importFn,
loaded: false,
component: null
});
}
// 动态加载路由组件
async loadRoute(path) {
const route = this.routes.get(path);
if (!route) {
throw new Error(`Route not found: ${path}`);
}
// 如果已经加载,直接返回
if (route.loaded) {
return route.component;
}
// 如果正在加载,返回现有的 Promise
if (this.loadingPromises.has(path)) {
return this.loadingPromises.get(path);
}
// 开始加载
const loadPromise = this.loadRouteComponent(route);
this.loadingPromises.set(path, loadPromise);
try {
const component = await loadPromise;
route.component = component;
route.loaded = true;
return component;
} finally {
this.loadingPromises.delete(path);
}
}
async loadRouteComponent(route) {
try {
// 显示加载状态
this.showLoadingState();
const module = await route.import();
// 预加载相关资源
await this.preloadRouteAssets(module);
return module.default;
} catch (error) {
console.error('路由加载失败:', error);
throw error;
} finally {
this.hideLoadingState();
}
}
// 预加载相关资源
async preloadRouteAssets(module) {
if (module.preloadAssets) {
const assets = module.preloadAssets();
await Promise.allSettled(assets.map(asset => this.preloadAsset(asset)));
}
}
preloadAsset(asset) {
return new Promise((resolve, reject) => {
if (asset.type === 'script') {
const script = document.createElement('script');
script.src = asset.src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
} else if (asset.type === 'style') {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = asset.src;
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
}
});
}
// 路由预加载策略
setupRoutePreloading() {
// 鼠标悬停时预加载
document.addEventListener('mouseover', (e) => {
const link = e.target.closest('a[data-route]');
if (link) {
const route = link.dataset.route;
this.preloadRoute(route);
}
});
// 空闲时预加载重要路由
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
this.preloadImportantRoutes();
});
}
}
async preloadRoute(path) {
try {
await this.loadRoute(path);
} catch (error) {
// 预加载失败不影响正常流程
console.warn('路由预加载失败:', path, error);
}
}
preloadImportantRoutes() {
const importantRoutes = ['/dashboard', '/profile', '/settings'];
importantRoutes.forEach(route => {
if (this.routes.has(route)) {
this.preloadRoute(route);
}
});
}
showLoadingState() {
document.body.classList.add('route-loading');
}
hideLoadingState() {
document.body.classList.remove('route-loading');
}
}
// 使用示例
const routeManager = new RouteManager();
// 注册路由
routeManager.registerRoute('/', () => import('./pages/Home.js'));
routeManager.registerRoute('/about', () => import('./pages/About.js'));
routeManager.registerRoute('/dashboard', () => import('./pages/Dashboard.js'));
// 设置预加载策略
routeManager.setupRoutePreloading();
Service Worker 为我们提供了强大的缓存能力:
// service-worker.js
class CacheManager {
constructor() {
this.CACHE_NAME = 'app-cache-v1';
this.STATIC_CACHE = 'static-cache-v1';
this.DYNAMIC_CACHE = 'dynamic-cache-v1';
this.STATIC_FILES = [
'/',
'/css/main.css',
'/js/main.js',
'/images/logo.png'
];
}
async install() {
const cache = await caches.open(this.STATIC_CACHE);
return cache.addAll(this.STATIC_FILES);
}
async activate() {
const cacheNames = await caches.keys();
const deletePromises = cacheNames
.filter(name => name !== this.STATIC_CACHE && name !== this.DYNAMIC_CACHE)
.map(name => caches.delete(name));
return Promise.all(deletePromises);
}
async handleFetch(event) {
const request = event.request;
const url = new URL(request.url);
// 静态资源缓存优先
if (this.isStaticAsset(url)) {
return this.cacheFirst(request);
}
// API 请求网络优先
if (this.isAPIRequest(url)) {
return this.networkFirst(request);
}
// 页面请求 stale-while-revalidate
if (this.isPageRequest(request)) {
return this.staleWhileRevalidate(request);
}
// 默认策略
return fetch(request);
}
async cacheFirst(request) {
const cached = await caches.match(request);
if (cached) {
return cached;
}
try {
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(this.STATIC_CACHE);
cache.put(request, response.clone());
}
return response;
} catch (error) {
console.error('Cache first strategy failed:', error);
throw error;
}
}
async networkFirst(request) {
try {
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(this.DYNAMIC_CACHE);
cache.put(request, response.clone());
}
return response;
} catch (error) {
const cached = await caches.match(request);
if (cached) {
return cached;
}
throw error;
}
}
async staleWhileRevalidate(request) {
const cached = await caches.match(request);
const fetchPromise = fetch(request).then(response => {
if (response.ok) {
const cache = caches.open(this.DYNAMIC_CACHE);
cache.then(c => c.put(request, response.clone()));
}
return response;
});
return cached || fetchPromise;
}
isStaticAsset(url) {
return /\.(css|js|png|jpg|jpeg|gif|svg|woff|woff2)$/.test(url.pathname);
}
isAPIRequest(url) {
return url.pathname.startsWith('/api/');
}
isPageRequest(request) {
return request.method === 'GET' && request.headers.get('accept').includes('text/html');
}
}
const cacheManager = new CacheManager();
self.addEventListener('install', (event) => {
event.waitUntil(cacheManager.install());
});
self.addEventListener('activate', (event) => {
event.waitUntil(cacheManager.activate());
});
self.addEventListener('fetch', (event) => {
event.respondWith(cacheManager.handleFetch(event));
});
// 资源优化管理器
class ResourceOptimizer {
constructor() {
this.criticalResources = new Set();
this.preloadQueue = [];
this.connectionPool = new Map();
}
// 关键资源预加载
preloadCriticalResources(resources) {
resources.forEach(resource => {
const link = document.createElement('link');
link.rel = 'preload';
link.href = resource.url;
link.as = resource.type;
if (resource.type === 'font') {
link.crossOrigin = 'anonymous';
}
document.head.appendChild(link);
this.criticalResources.add(resource.url);
});
}
// DNS 预解析
preconnectToDomains(domains) {
domains.forEach(domain => {
const link = document.createElement('link');
link.rel = 'preconnect';
link.href = domain;
link.crossOrigin = 'anonymous';
document.head.appendChild(link);
});
}
// 资源压缩检查
checkResourceCompression() {
const resources = performance.getEntriesByType('resource');
const uncompressedResources = [];
resources.forEach(resource => {
if (resource.transferSize > resource.encodedBodySize * 0.9) {
uncompressedResources.push({
url: resource.name,
size: resource.transferSize,
type: this.getResourceType(resource.name)
});
}
});
if (uncompressedResources.length > 0) {
console.warn('发现未压缩的资源:', uncompressedResources);
}
return uncompressedResources;
}
getResourceType(url) {
const extension = url.split('.').pop().toLowerCase();
const typeMap = {
'js': 'script',
'css': 'stylesheet',
'png': 'image',
'jpg': 'image',
'jpeg': 'image',
'gif': 'image',
'svg': 'image',
'woff': 'font',
'woff2': 'font',
'ttf': 'font'
};
return typeMap[extension] || 'other';
}
// 资源加载优先级管理
setPriorityHints() {
// 为关键资源设置高优先级
document.querySelectorAll('link[rel="stylesheet"]').forEach(link => {
if (this.criticalResources.has(link.href)) {
link.setAttribute('importance', 'high');
}
});
// 为非关键图片设置低优先级
document.querySelectorAll('img[data-src]').forEach(img => {
img.setAttribute('importance', 'low');
});
}
// 监控资源加载性能
monitorResourceLoading() {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach(entry => {
if (entry.duration > 1000) { // 加载时间超过1秒
console.warn('慢速资源:', {
url: entry.name,
duration: entry.duration,
size: entry.transferSize
});
}
});
});
observer.observe({ entryTypes: ['resource'] });
}
}
// 使用示例
const optimizer = new ResourceOptimizer();
// 预加载关键资源
optimizer.preloadCriticalResources([
{ url: '/css/critical.css', type: 'style' },
{ url: '/js/main.js', type: 'script' },
{ url: '/fonts/main.woff2', type: 'font' }
]);
// 预连接到外部域名
optimizer.preconnectToDomains([
'https://fonts.googleapis.com',
'https://api.example.com',
'https://cdn.example.com'
]);
// 开始监控
optimizer.monitorResourceLoading();
// 性能监控和分析系统
class PerformanceAnalyzer {
constructor() {
this.metrics = {
navigation: {},
resources: [],
userInteractions: [],
errors: []
};
this.thresholds = {
lcp: 2500,
fid: 100,
cls: 0.1,
ttfb: 600
};
this.initMonitoring();
}
initMonitoring() {
this.monitorNavigation();
this.monitorResources();
this.monitorUserInteractions();
this.monitorErrors();
this.setupReporting();
}
monitorNavigation() {
// 监控导航时间
window.addEventListener('load', () => {
const navigation = performance.getEntriesByType('navigation')[0];
this.metrics.navigation = {
dns: navigation.domainLookupEnd - navigation.domainLookupStart,
tcp: navigation.connectEnd - navigation.connectStart,
ttfb: navigation.responseStart - navigation.requestStart,
domContentLoaded: navigation.domContentLoadedEventEnd - navigation.navigationStart,
loadComplete: navigation.loadEventEnd - navigation.navigationStart
};
this.analyzeNavigationPerformance();
});
}
monitorResources() {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach(entry => {
this.metrics.resources.push({
name: entry.name,
type: entry.initiatorType,
size: entry.transferSize,
duration: entry.duration,
startTime: entry.startTime
});
});
});
observer.observe({ entryTypes: ['resource'] });
}
monitorUserInteractions() {
// 监控点击响应时间
document.addEventListener('click', (event) => {
const startTime = performance.now();
requestAnimationFrame(() => {
const endTime = performance.now();
const responseTime = endTime - startTime;
this.metrics.userInteractions.push({
type: 'click',
target: event.target.tagName,
responseTime,
timestamp: Date.now()
});
if (responseTime > this.thresholds.fid) {
this.reportSlowInteraction(event.target, responseTime);
}
});
});
}
monitorErrors() {
// 监控JavaScript错误
window.addEventListener('error', (event) => {
this.metrics.errors.push({
type: 'javascript',
message: event.message,
filename: event.filename,
line: event.lineno,
column: event.colno,
timestamp: Date.now()
});
});
// 监控资源加载错误
window.addEventListener('error', (event) => {
if (event.target !== window) {
this.metrics.errors.push({
type: 'resource',
element: event.target.tagName,
source: event.target.src || event.target.href,
timestamp: Date.now()
});
}
}, true);
}
analyzeNavigationPerformance() {
const nav = this.metrics.navigation;
const issues = [];
if (nav.dns > 200) {
issues.push('DNS解析时间过长');
}
if (nav.tcp > 500) {
issues.push('TCP连接时间过长');
}
if (nav.ttfb > this.thresholds.ttfb) {
issues.push('服务器响应时间过长');
}
if (issues.length > 0) {
console.warn('性能问题:', issues);
this.reportPerformanceIssues(issues);
}
}
reportSlowInteraction(target, responseTime) {
console.warn('慢速交互:', {
element: target.tagName,
responseTime: `${responseTime.toFixed(2)}ms`,
threshold: `${this.thresholds.fid}ms`
});
}
reportPerformanceIssues(issues) {
// 发送性能问题报告
fetch('/api/performance-issues', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
issues,
metrics: this.metrics,
userAgent: navigator.userAgent,
timestamp: Date.now()
})
}).catch(err => console.error('性能报告发送失败:', err));
}
setupReporting() {
// 定期发送性能报告
setInterval(() => {
this.sendPerformanceReport();
}, 30000); // 每30秒发送一次
// 页面卸载时发送报告
window.addEventListener('beforeunload', () => {
this.sendPerformanceReport();
});
}
sendPerformanceReport() {
const report = {
metrics: this.metrics,
url: window.location.href,
timestamp: Date.now(),
connection: this.getConnectionInfo()
};
// 使用 sendBeacon 确保数据能够发送
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/performance', JSON.stringify(report));
} else {
fetch('/api/performance', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(report)
}).catch(err => console.error('性能报告发送失败:', err));
}
}
getConnectionInfo() {
if ('connection' in navigator) {
return {
effectiveType: navigator.connection.effectiveType,
downlink: navigator.connection.downlink,
rtt: navigator.connection.rtt,
saveData: navigator.connection.saveData
};
}
return null;
}
// 生成性能报告
generateReport() {
const report = {
summary: this.generateSummary(),
details: this.metrics,
recommendations: this.generateRecommendations()
};
console.table(report.summary);
return report;
}
generateSummary() {
const nav = this.metrics.navigation;
const resources = this.metrics.resources;
return {
'首次字节时间': `${nav.ttfb || 0}ms`,
'DOM加载完成': `${nav.domContentLoaded || 0}ms`,
'页面加载完成': `${nav.loadComplete || 0}ms`,
'资源总数': resources.length,
'资源总大小': this.formatBytes(resources.reduce((sum, r) => sum + r.size, 0)),
'交互次数': this.metrics.userInteractions.length,
'错误数量': this.metrics.errors.length
};
}
generateRecommendations() {
const recommendations = [];
const nav = this.metrics.navigation;
const resources = this.metrics.resources;
if (nav.ttfb > this.thresholds.ttfb) {
recommendations.push('优化服务器响应时间');
}
const largeResources = resources.filter(r => r.size > 1024 * 1024);
if (largeResources.length > 0) {
recommendations.push('压缩大型资源文件');
}
const slowResources = resources.filter(r => r.duration > 1000);
if (slowResources.length > 0) {
recommendations.push('优化慢速加载的资源');
}
return recommendations;
}
formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
}
// 初始化性能监控
const analyzer = new PerformanceAnalyzer();
// 在控制台中查看性能报告
window.getPerformanceReport = () => analyzer.generateReport();
前端性能优化是一个系统工程,需要从多个维度协同优化:
关键要点:
实施建议:
性能优化没有银弹,但通过系统性的方法和持续的监控,我们可以为用户提供更好的体验。记住,每减少100ms的加载时间,都可能带来1%的转化率提升。