性能优化

性能优化概述

性能优化是Web开发中的重要环节,直接影响用户体验和业务指标。

东巴文(db-w.cn) 认为:性能优化不是一次性工作,而是持续的过程。掌握性能分析工具、优化策略和最佳实践,能显著提升Web应用的加载速度和运行效率,为用户提供更好的体验。

性能指标

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>性能优化概述 - 东巴文</title>
    
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 20px;
        }
        
        h2 {
            color: #764ba2;
            margin: 30px 0 15px;
            border-left: 4px solid #764ba2;
            padding-left: 15px;
        }
        
        .perf-demo {
            background: #f8f9fa;
            padding: 20px;
            border: 2px solid #ddd;
            margin: 15px 0;
            border-radius: 10px;
        }
        
        .perf-demo h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .metrics-table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }
        
        .metrics-table th,
        .metrics-table td {
            padding: 12px;
            text-align: left;
            border: 1px solid #ddd;
        }
        
        .metrics-table th {
            background: #667eea;
            color: white;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>性能优化概述</h1>
        
        <h2>核心性能指标</h2>
        
        <table class="metrics-table">
            <thead>
                <tr>
                    <th>指标</th>
                    <th>全称</th>
                    <th>含义</th>
                    <th>目标值</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><strong>FCP</strong></td>
                    <td>First Contentful Paint</td>
                    <td>首次内容绘制</td>
                    <td>&lt; 1.8s</td>
                </tr>
                <tr>
                    <td><strong>LCP</strong></td>
                    <td>Largest Contentful Paint</td>
                    <td>最大内容绘制</td>
                    <td>&lt; 2.5s</td>
                </tr>
                <tr>
                    <td><strong>FID</strong></td>
                    <td>First Input Delay</td>
                    <td>首次输入延迟</td>
                    <td>&lt; 100ms</td>
                </tr>
                <tr>
                    <td><strong>CLS</strong></td>
                    <td>Cumulative Layout Shift</td>
                    <td>累积布局偏移</td>
                    <td>&lt; 0.1</td>
                </tr>
                <tr>
                    <td><strong>TTFB</strong></td>
                    <td>Time to First Byte</td>
                    <td>首字节时间</td>
                    <td>&lt; 600ms</td>
                </tr>
                <tr>
                    <td><strong>TTI</strong></td>
                    <td>Time to Interactive</td>
                    <td>可交互时间</td>
                    <td>&lt; 3.8s</td>
                </tr>
                <tr>
                    <td><strong>TBT</strong></td>
                    <td>Total Blocking Time</td>
                    <td>总阻塞时间</td>
                    <td>&lt; 200ms</td>
                </tr>
                <tr>
                    <td><strong>SI</strong></td>
                    <td>Speed Index</td>
                    <td>速度指数</td>
                    <td>&lt; 3.4s</td>
                </tr>
            </tbody>
        </table>
        
        <h2>性能测量工具</h2>
        
        <div class="perf-demo">
            <h3>常用工具</h3>
            <div style="background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; margin: 10px 0;">
                <pre>
1. Chrome DevTools
   - Performance面板:记录和分析运行时性能
   - Network面板:分析网络请求
   - Lighthouse:综合性能审计
   - Coverage:代码覆盖率分析

2. WebPageTest
   - 多地点测试
   - 瀑布流分析
   - 视频录制
   - 性能评分

3. Lighthouse
   - 性能评分
   - 最佳实践检查
   - SEO检查
   - 可访问性检查

4. PageSpeed Insights
   - Core Web Vitals评估
   - 优化建议
   - 移动端和桌面端分析

5. Web Vitals库
   - 实时性能监控
   - 真实用户数据(RUM)
   - 自动上报
                </pre>
            </div>
        </div>
        
        <h2>性能测量API</h2>
        
        <div class="perf-demo">
            <h3>Performance API</h3>
            <div style="background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; margin: 10px 0;">
                <pre>
// 1. Performance Timeline API
// 测量代码执行时间
performance.mark('start');
// ... 执行代码
performance.mark('end');
performance.measure('My Measure', 'start', 'end');

const measures = performance.getEntriesByName('My Measure');
console.log('执行时间:', measures[0].duration, 'ms');

// 2. Navigation Timing API
// 页面加载性能
const timing = performance.timing;
const loadTime = timing.loadEventEnd - timing.navigationStart;
const domReady = timing.domContentLoadedEventEnd - timing.navigationStart;
const ttfb = timing.responseStart - timing.navigationStart;

console.log('页面加载时间:', loadTime, 'ms');
console.log('DOM Ready:', domReady, 'ms');
console.log('TTFB:', ttfb, 'ms');

// 3. Resource Timing API
// 资源加载性能
const resources = performance.getEntriesByType('resource');
resources.forEach(resource =&gt; {
    console.log(resource.name, resource.duration, 'ms');
});

// 4. User Timing API
// 自定义性能标记
performance.mark('feature-start');
// ... 功能代码
performance.mark('feature-end');
performance.measure('feature', 'feature-start', 'feature-end');

// 5. Performance Observer
// 监听性能事件
const observer = new PerformanceObserver((list) =&gt; {
    list.getEntries().forEach(entry =&gt; {
        console.log(entry.name, entry.entryType, entry.startTime, entry.duration);
    });
});

observer.observe({ entryTypes: ['measure', 'resource', 'paint'] });
                </pre>
            </div>
        </div>
        
        <h2>Web Vitals监控</h2>
        
        <div class="perf-demo">
            <h3>使用web-vitals库</h3>
            <div style="background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; margin: 10px 0;">
                <pre>
// 安装: npm install web-vitals

import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

// 监控CLS
getCLS(console.log);

// 监控FID
getFID(console.log);

// 监控FCP
getFCP(console.log);

// 监控LCP
getLCP(console.log);

// 监控TTFB
getTTFB(console.log);

// 发送到分析服务
function sendToAnalytics(metric) {
    const body = JSON.stringify({
        name: metric.name,
        value: metric.value,
        delta: metric.delta,
        id: metric.id,
    });
    
    // 使用navigator.sendBeacon确保发送
    if (navigator.sendBeacon) {
        navigator.sendBeacon('/analytics', body);
    } else {
        fetch('/analytics', {
            body,
            method: 'POST',
            keepalive: true
        });
    }
}

// 应用到所有指标
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
                </pre>
            </div>
        </div>
        
        <div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
            <strong>东巴文提示:</strong>性能优化的第一步是测量。掌握Core Web Vitals指标、性能测量工具和API,能准确识别性能瓶颈,为优化提供数据支持。
        </div>
    </div>
</body>
</html>

加载性能优化

加载性能优化关注如何让页面更快地显示内容。

优化策略

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加载性能优化 - 东巴文</title>
    
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 20px;
        }
        
        h2 {
            color: #764ba2;
            margin: 30px 0 15px;
            border-left: 4px solid #764ba2;
            padding-left: 15px;
        }
        
        .loading-demo {
            background: #f8f9fa;
            padding: 20px;
            border: 2px solid #ddd;
            margin: 15px 0;
            border-radius: 10px;
        }
        
        .loading-demo h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .code-block {
            background: #2d2d2d;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>加载性能优化</h1>
        
        <h2>资源压缩</h2>
        
        <div class="loading-demo">
            <h3>代码压缩</h3>
            <div class="code-block">
                <pre>
// JavaScript压缩(使用Terser)
// 安装: npm install terser -D

// terser.config.js
module.exports = {
    compress: {
        drop_console: true,  // 移除console
        drop_debugger: true, // 移除debugger
        pure_funcs: ['console.log'] // 移除特定函数
    },
    mangle: {
        toplevel: true // 顶级作用域变量混淆
    },
    format: {
        comments: false // 移除注释
    }
};

// CSS压缩(使用cssnano)
// 安装: npm install cssnano -D

// postcss.config.js
module.exports = {
    plugins: [
        require('cssnano')({
            preset: 'advanced'
        })
    ]
};

// HTML压缩(使用html-minifier)
// 安装: npm install html-minifier -D

const htmlMinifier = require('html-minifier');
const minified = htmlMinifier.minify(html, {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true,
    minifyCSS: true,
    minifyJS: true
});
                </pre>
            </div>
        </div>
        
        <h2>代码分割</h2>
        
        <div class="loading-demo">
            <h3>动态导入</h3>
            <div class="code-block">
                <pre>
// 1. 动态import()
// 路由懒加载
const routes = [
    {
        path: '/home',
        component: () =&gt; import('./views/Home.vue')
    },
    {
        path: '/about',
        component: () =&gt; import('./views/About.vue')
    }
];

// 条件加载
async function loadModule() {
    if (condition) {
        const module = await import('./heavy-module.js');
        module.doSomething();
    }
}

// 2. Webpack代码分割
// webpack.config.js
module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'all'
                },
                common: {
                    name: 'common',
                    minChunks: 2,
                    chunks: 'initial',
                    priority: -10
                }
            }
        }
    }
};

// 3. React.lazy
import React, { Suspense, lazy } from 'react';

const LazyComponent = lazy(() =&gt; import('./LazyComponent'));

function App() {
    return (
        &lt;Suspense fallback={&lt;div&gt;Loading...&lt;/div&gt;}&gt;
            &lt;LazyComponent /&gt;
        &lt;/Suspense&gt;
    );
}

// 4. Vue异步组件
const AsyncComponent = () =&gt; ({
    component: import('./AsyncComponent.vue'),
    loading: LoadingComponent,
    error: ErrorComponent,
    delay: 200,
    timeout: 3000
});
                </pre>
            </div>
        </div>
        
        <h2>资源预加载</h2>
        
        <div class="loading-demo">
            <h3>预加载策略</h3>
            <div class="code-block">
                <pre>
&lt;!-- 1. preload:预加载当前页面必需资源 --&gt;
&lt;link rel="preload" href="critical.css" as="style"&gt;
&lt;link rel="preload" href="main.js" as="script"&gt;
&lt;link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin&gt;
&lt;link rel="preload" href="hero.jpg" as="image"&gt;

&lt;!-- 2. prefetch:预取未来可能需要的资源 --&gt;
&lt;link rel="prefetch" href="next-page.js" as="script"&gt;
&lt;link rel="prefetch" href="detail.html" as="document"&gt;

&lt;!-- 3. preconnect:预连接域名 --&gt;
&lt;link rel="preconnect" href="https://cdn.example.com"&gt;
&lt;link rel="dns-prefetch" href="https://cdn.example.com"&gt;

&lt;!-- 4. modulepreload:预加载ES模块 --&gt;
&lt;link rel="modulepreload" href="module.js"&gt;

&lt;!-- 5. 预加载关键字体 --&gt;
&lt;style&gt;
@font-face {
    font-family: 'MyFont';
    src: url('font.woff2') format('woff2');
    font-display: swap; /* 字体加载策略 */
}
&lt;/style&gt;

&lt;!-- 6. 预加载关键CSS --&gt;
&lt;style&gt;
    /* 内联关键CSS */
    body { margin: 0; font-family: sans-serif; }
    .header { background: #667eea; }
&lt;/style&gt;
&lt;link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'"&gt;
                </pre>
            </div>
        </div>
        
        <h2>图片优化</h2>
        
        <div class="loading-demo">
            <h3>图片加载优化</h3>
            <div class="code-block">
                <pre>
&lt;!-- 1. 响应式图片 --&gt;
&lt;img 
    src="image.jpg"
    srcset="image-320.jpg 320w,
            image-640.jpg 640w,
            image-1280.jpg 1280w"
    sizes="(max-width: 640px) 100vw,
           (max-width: 1024px) 50vw,
           33vw"
    alt="响应式图片"
&gt;

&lt;!-- 2. 懒加载 --&gt;
&lt;img src="placeholder.jpg" data-src="image.jpg" loading="lazy" alt="懒加载图片"&gt;

&lt;!-- 3. 现代图片格式 --&gt;
&lt;picture&gt;
    &lt;source srcset="image.avif" type="image/avif"&gt;
    &lt;source srcset="image.webp" type="image/webp"&gt;
    &lt;img src="image.jpg" alt="降级图片"&gt;
&lt;/picture&gt;

&lt;!-- 4. 占位符 --&gt;
&lt;img 
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600'%3E%3Crect fill='%23f0f0f0' width='800' height='600'/%3E%3C/svg%3E"
    data-src="image.jpg"
    class="lazy"
    alt="占位符图片"
&gt;

&lt;!-- 5. 低质量图片占位符(LQIP) --&gt;
&lt;img 
    src="image-tiny.jpg"
    data-src="image-full.jpg"
    class="blur-up"
    alt="渐进式图片"
&gt;

&lt;!-- 6. 懒加载JavaScript实现 --&gt;
&lt;script&gt;
const images = document.querySelectorAll('img[data-src]');

const imageObserver = new IntersectionObserver((entries, observer) =&gt; {
    entries.forEach(entry =&gt; {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.removeAttribute('data-src');
            observer.unobserve(img);
        }
    });
}, {
    rootMargin: '50px 0px',
    threshold: 0.01
});

images.forEach(img =&gt; imageObserver.observe(img));
&lt;/script&gt;
                </pre>
            </div>
        </div>
        
        <h2>缓存策略</h2>
        
        <div class="loading-demo">
            <h3>HTTP缓存</h3>
            <div class="code-block">
                <pre>
// 服务端缓存配置(Nginx)
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(html)$ {
    expires -1;
    add_header Cache-Control "no-cache, no-store, must-revalidate";
}

// Service Worker缓存
const CACHE_NAME = 'v1';
const STATIC_ASSETS = [
    '/',
    '/styles/main.css',
    '/scripts/main.js',
    '/images/logo.png'
];

self.addEventListener('install', event =&gt; {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache =&gt; cache.addAll(STATIC_ASSETS))
    );
});

self.addEventListener('fetch', event =&gt; {
    event.respondWith(
        caches.match(event.request)
            .then(response =&gt; response || fetch(event.request))
    );
});

// 版本化资源
// 使用内容哈希命名
// main.a1b2c3d4.js
// styles.e5f6g7h8.css
                </pre>
            </div>
        </div>
        
        <div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
            <strong>东巴文提示:</strong>加载性能优化是用户体验的第一道关卡。通过资源压缩、代码分割、预加载、图片优化和缓存策略,能显著提升页面加载速度,改善FCP、LCP等关键指标。
        </div>
    </div>
</body>
</html>

运行时性能优化

运行时性能优化关注页面运行时的流畅度和响应速度。

优化策略

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>运行时性能优化 - 东巴文</title>
    
    <style>
        body {
            font-family: 'Segoe UI', sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }
        
        h1 {
            color: #667eea;
            margin-bottom: 20px;
        }
        
        h2 {
            color: #764ba2;
            margin: 30px 0 15px;
            border-left: 4px solid #764ba2;
            padding-left: 15px;
        }
        
        .runtime-demo {
            background: #f8f9fa;
            padding: 20px;
            border: 2px solid #ddd;
            margin: 15px 0;
            border-radius: 10px;
        }
        
        .runtime-demo h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .code-block {
            background: #2d2d2d;
            color: #f8f8f2;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>运行时性能优化</h1>
        
        <h2>避免长任务</h2>
        
        <div class="runtime-demo">
            <h3>任务分片</h3>
            <div class="code-block">
                <pre>
// ❌ 长任务阻塞主线程
function processLargeArray(array) {
    for (let i = 0; i &lt; array.length; i++) {
        // 处理每个元素
        processItem(array[i]);
    }
}

// ✅ 使用requestIdleCallback分片处理
function processLargeArrayAsync(array, callback) {
    let i = 0;
    
    function processChunk(deadline) {
        while (i &lt; array.length &amp;&amp; deadline.timeRemaining() &gt; 0) {
            processItem(array[i]);
            i++;
        }
        
        if (i &lt; array.length) {
            requestIdleCallback(processChunk);
        } else {
            callback();
        }
    }
    
    requestIdleCallback(processChunk);
}

// ✅ 使用setTimeout分片
function processLargeArrayChunked(array, chunkSize = 100) {
    let i = 0;
    
    function processChunk() {
        const end = Math.min(i + chunkSize, array.length);
        
        while (i &lt; end) {
            processItem(array[i]);
            i++;
        }
        
        if (i &lt; array.length) {
            setTimeout(processChunk, 0);
        }
    }
    
    processChunk();
}

// ✅ 使用Web Worker
const worker = new Worker('processor.js');

worker.postMessage({ type: 'process', data: largeArray });

worker.onmessage = (e) =&gt; {
    console.log('处理完成:', e.data);
};

// processor.js
self.onmessage = (e) =&gt; {
    if (e.data.type === 'process') {
        const result = processArray(e.data.data);
        self.postMessage({ type: 'result', data: result });
    }
};
                </pre>
            </div>
        </div>
        
        <h2>虚拟列表</h2>
        
        <div class="runtime-demo">
            <h3>大列表渲染优化</h3>
            <div class="code-block">
                <pre>
class VirtualList {
    constructor(options) {
        this.container = options.container;
        this.itemHeight = options.itemHeight;
        this.renderItem = options.renderItem;
        this.data = options.data || [];
        
        this.visibleCount = Math.ceil(this.container.clientHeight / this.itemHeight);
        this.startIndex = 0;
        this.endIndex = this.visibleCount;
        
        this.init();
    }
    
    init() {
        // 创建容器
        this.wrapper = document.createElement('div');
        this.wrapper.style.cssText = `
            position: relative;
            height: ${this.data.length * this.itemHeight}px;
        `;
        
        this.content = document.createElement('div');
        this.content.style.cssText = `
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
        `;
        
        this.wrapper.appendChild(this.content);
        this.container.appendChild(this.wrapper);
        
        // 监听滚动
        this.container.addEventListener('scroll', this.handleScroll.bind(this));
        
        // 初始渲染
        this.render();
    }
    
    handleScroll() {
        const scrollTop = this.container.scrollTop;
        this.startIndex = Math.floor(scrollTop / this.itemHeight);
        this.endIndex = this.startIndex + this.visibleCount + 2; // 缓冲2个
        
        this.render();
    }
    
    render() {
        const visibleData = this.data.slice(
            Math.max(0, this.startIndex - 2),
            Math.min(this.data.length, this.endIndex + 2)
        );
        
        this.content.style.transform = `translateY(${this.startIndex * this.itemHeight}px)`;
        this.content.innerHTML = visibleData.map((item, index) =&gt; 
            this.renderItem(item, this.startIndex + index)
        ).join('');
    }
}

// 使用示例
const virtualList = new VirtualList({
    container: document.getElementById('list-container'),
    itemHeight: 50,
    data: Array.from({ length: 10000 }, (_, i) =&gt; ({ id: i, name: `Item ${i}` })),
    renderItem: (item, index) =&gt; `
        &lt;div style="height: 50px; border-bottom: 1px solid #eee; padding: 10px;"&gt;
            ${item.name}
        &lt;/div&gt;
    `
});
                </pre>
            </div>
        </div>
        
        <h2>防抖与节流</h2>
        
        <div class="runtime-demo">
            <h3>函数优化</h3>
            <div class="code-block">
                <pre>
// 防抖(Debounce)
function debounce(func, wait, immediate = false) {
    let timeout;
    
    return function(...args) {
        const context = this;
        
        const later = () =&gt; {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        
        const callNow = immediate &amp;&amp; !timeout;
        
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        
        if (callNow) func.apply(context, args);
    };
}

// 使用
const debouncedSearch = debounce((query) =&gt; {
    fetchSearchResults(query);
}, 300);

input.addEventListener('input', (e) =&gt; {
    debouncedSearch(e.target.value);
});

// 节流(Throttle)
function throttle(func, limit) {
    let inThrottle;
    
    return function(...args) {
        const context = this;
        
        if (!inThrottle) {
            func.apply(context, args);
            inThrottle = true;
            setTimeout(() =&gt; inThrottle = false, limit);
        }
    };
}

// 使用
const throttledScroll = throttle(() =&gt; {
    console.log('Scroll position:', window.scrollY);
}, 100);

window.addEventListener('scroll', throttledScroll);

// requestAnimationFrame节流
function rafThrottle(func) {
    let ticking = false;
    
    return function(...args) {
        if (!ticking) {
            requestAnimationFrame(() =&gt; {
                func.apply(this, args);
                ticking = false;
            });
            ticking = true;
        }
    };
}

// 使用
const throttledResize = rafThrottle(() =&gt; {
    console.log('Window size:', window.innerWidth, window.innerHeight);
});

window.addEventListener('resize', throttledResize);
                </pre>
            </div>
        </div>
        
        <h2>内存管理</h2>
        
        <div class="runtime-demo">
            <h3>避免内存泄漏</h3>
            <div class="code-block">
                <pre>
// ❌ 未清理的事件监听器
class Component {
    constructor() {
        window.addEventListener('resize', this.handleResize);
    }
    
    handleResize = () =&gt; {
        // 处理resize
    }
}

// ✅ 清理事件监听器
class Component {
    constructor() {
        window.addEventListener('resize', this.handleResize);
    }
    
    handleResize = () =&gt; {
        // 处理resize
    }
    
    destroy() {
        window.removeEventListener('resize', this.handleResize);
    }
}

// ❌ 未清理的定时器
class Timer {
    constructor() {
        this.timer = setInterval(() =&gt; {
            this.update();
        }, 1000);
    }
    
    update() {
        // 更新
    }
}

// ✅ 清理定时器
class Timer {
    constructor() {
        this.timer = setInterval(() =&gt; {
            this.update();
        }, 1000);
    }
    
    update() {
        // 更新
    }
    
    destroy() {
        clearInterval(this.timer);
    }
}

// ❌ 闭包引用
function createClosure() {
    const largeData = new Array(1000000).fill('data');
    
    return function() {
        console.log(largeData.length); // 持有largeData引用
    };
}

// ✅ 避免不必要的引用
function createClosure() {
    const largeData = new Array(1000000).fill('data');
    const length = largeData.length;
    
    return function() {
        console.log(length); // 只持有需要的值
    };
}

// ✅ 使用WeakMap避免强引用
const cache = new WeakMap();

function cacheData(obj, data) {
    cache.set(obj, data);
}

function getData(obj) {
    return cache.get(obj);
}

// 当obj被垃圾回收时,cache中的数据也会被清理
                </pre>
            </div>
        </div>
        
        <div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
            <strong>东巴文提示:</strong>运行时性能优化关注页面的流畅度和响应速度。通过避免长任务、虚拟列表、防抖节流、内存管理等技术,能显著改善FID、TBT等指标,提升用户体验。
        </div>
    </div>
</body>
</html>

学习检验

完成本章学习后,请尝试回答以下问题:

  1. 选择题: Core Web Vitals包括哪些指标?

    • A. FCP, LCP, TTFB
    • B. LCP, FID, CLS
    • C. TTI, TBT, SI
    • D. FCP, FID, TTI
  2. 填空题: ____用于预加载当前页面必需的资源,____用于预取未来可能需要的资源。

  3. 简答题: 什么是虚拟列表?它解决了什么问题?

  4. 实践题: 使用Lighthouse分析一个网页的性能,找出性能瓶颈并提出优化建议。

  5. 应用题: 分析一个性能优化的实际案例(如淘宝、京东),总结其优化策略和效果。