avatar
Siz Long

My name is Siz. I am a computer science graduate student specializing in backend development with Golang and Python, seeking opportunities in innovative tech projects. My personal website is me.longsizhuo.com .Connect with me on LinkedIn: https://www.linkedin.com/in/longsizhuo/.

  • Resume
  • Archives
  • Categories
  • Photos
  • Music



{{ date }}

{{ time }}

avatar
Siz Long

My name is Siz. I am a computer science graduate student specializing in backend development with Golang and Python, seeking opportunities in innovative tech projects. My personal website is me.longsizhuo.com .Connect with me on LinkedIn: https://www.linkedin.com/in/longsizhuo/.

  • 主页
  • Resume
  • Archives
  • Categories
  • Photos
  • Music

Frontend Performance Optimization

  2023-06-16        
字数统计: 2.9k字   |   阅读时长: 18min

Frontend Performance Optimization

Performance is a critical aspect of user experience. This guide covers key techniques and metrics for optimizing frontend applications.

Core Web Vitals

Core Web Vitals are a set of user-centric metrics that measure real-world user experience.

Largest Contentful Paint (LCP)

LCP measures loading performance – how quickly the largest content element becomes visible.

Good LCP Scores

  • Good: ≤ 2.5 seconds
  • Needs Improvement: 2.5 - 4.0 seconds
  • Poor: > 4.0 seconds

Improving LCP

  1. Optimize Server Response Time

    • Use a CDN
    • Implement caching
    • Optimize backend code
    • Use early hints (103 Early Hints)
  2. Optimize Resource Loading

    1
    2
    3
    4
    5
    <!-- Preload critical resources -->
    <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

    <!-- Preconnect to required origins -->
    <link rel="preconnect" href="https://cdn.example.com">
  3. Eliminate Render-Blocking Resources

    1
    2
    3
    4
    5
    <!-- Defer non-critical JavaScript -->
    <script src="/js/non-critical.js" defer></script>

    <!-- Load non-critical CSS asynchronously -->
    <link rel="preload" href="/css/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  4. Optimize Images

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!-- Use responsive images -->
    <img
    src="image-400w.jpg"
    srcset="image-400w.jpg 400w, image-800w.jpg 800w, image-1200w.jpg 1200w"
    sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
    alt="Responsive image"
    >

    <!-- Use modern formats -->
    <picture>
    <source type="image/avif" srcset="image.avif">
    <source type="image/webp" srcset="image.webp">
    <img src="image.jpg" alt="Image description">
    </picture>

First Input Delay (FID)

FID measures interactivity – how quickly a page responds to user interactions.

Good FID Scores

  • Good: ≤ 100ms
  • Needs Improvement: 100ms - 300ms
  • Poor: > 300ms

Improving FID

  1. Break Up Long Tasks

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // Instead of one long task
    function processAllItems(items) {
    for (const item of items) {
    processItem(item); // Potentially expensive operation
    }
    }

    // Break into smaller chunks with scheduling
    function processItemsInChunks(items, chunkSize = 50) {
    let index = 0;

    function processChunk() {
    const limit = Math.min(index + chunkSize, items.length);

    while (index < limit) {
    processItem(items[index++]);
    }

    if (index < items.length) {
    setTimeout(processChunk, 0); // Yield to browser
    }
    }

    processChunk();
    }
  2. Use Web Workers for Heavy Computation

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // main.js
    const worker = new Worker('worker.js');

    worker.addEventListener('message', (event) => {
    // Handle result from the worker
    displayResult(event.data);
    });

    // Send data to worker
    worker.postMessage({ data: complexData });

    // worker.js
    self.addEventListener('message', (event) => {
    // Perform heavy computation without blocking the main thread
    const result = performComplexCalculation(event.data);
    self.postMessage(result);
    });
  3. Optimize JavaScript Execution

    • Avoid unnecessary JavaScript
    • Code-split and lazy load components
    • Minimize unused polyfills
    • Use modern JavaScript syntax (which typically compiles to smaller code)

Cumulative Layout Shift (CLS)

CLS measures visual stability – how much elements move around during page load.

Good CLS Scores

  • Good: ≤ 0.1
  • Needs Improvement: 0.1 - 0.25
  • Poor: > 0.25

Improving CLS

  1. Set Size Attributes on Media

    1
    2
    3
    4
    5
    6
    7
    <!-- Always specify dimensions -->
    <img src="image.jpg" width="640" height="360" alt="Image with dimensions">

    <!-- Or use aspect ratio box -->
    <div style="aspect-ratio: 16/9; width: 100%;">
    <img src="image.jpg" style="width: 100%; height: 100%; object-fit: cover;">
    </div>
  2. Reserve Space for Dynamic Content

    1
    2
    3
    4
    5
    6
    /* For ads, embeds, etc. */
    .ad-container {
    min-height: 250px; /* Known minimum height */
    width: 100%;
    background-color: #f1f1f1;
    }
  3. Avoid Inserting Content Above Existing Content

    1
    2
    3
    4
    5
    6
    // Bad: Inserting a banner at the top after load
    document.body.insertBefore(banner, document.body.firstChild);

    // Better: Reserve the space or add at the bottom
    const bannerContainer = document.getElementById('banner-container');
    bannerContainer.appendChild(banner);
  4. Use CSS content-visibility for Long Pages

    1
    2
    3
    4
    5
    /* Skip rendering off-screen content */
    .content-section {
    content-visibility: auto;
    contain-intrinsic-size: 0 500px; /* Estimate size */
    }

Interaction to Next Paint (INP)

INP measures responsiveness – how quickly the page responds to all user interactions.

Good INP Scores

  • Good: ≤ 200ms
  • Needs Improvement: 200ms - 500ms
  • Poor: > 500ms

Improving INP

  1. Use Event Delegation

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Instead of adding listeners to each button
    document.querySelectorAll('.button').forEach(button => {
    button.addEventListener('click', handleClick);
    });

    // Use event delegation
    document.addEventListener('click', (event) => {
    if (event.target.matches('.button')) {
    handleClick(event);
    }
    });
  2. Debounce or Throttle Input Handlers

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function debounce(func, wait) {
    let timeout;
    return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
    };
    }

    // Apply to expensive handlers
    const debouncedSearchHandler = debounce((event) => {
    searchAPI(event.target.value);
    }, 300);

    searchInput.addEventListener('input', debouncedSearchHandler);
  3. Use CSS for Animations When Possible

    1
    2
    3
    4
    5
    6
    7
    8
    /* Use CSS transitions instead of JavaScript */
    .button {
    transition: transform 0.2s ease-out;
    }

    .button:hover {
    transform: scale(1.05);
    }

Rendering Performance

Critical Rendering Path

  1. HTML Parsing
  2. CSS Object Model (CSSOM)
  3. Render Tree Construction
  4. Layout/Reflow
  5. Paint
  6. Compositing

Reducing Layout Thrashing

Layout thrashing occurs when JavaScript repeatedly reads and writes to the DOM, forcing multiple recalculations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Bad: Interleaved reads and writes
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
const width = box.offsetWidth; // Read
box.style.width = (width * 2) + 'px'; // Write
const height = box.offsetHeight; // Read - forces reflow
box.style.height = (height * 2) + 'px'; // Write
});

// Good: Batch reads, then writes
const boxes = document.querySelectorAll('.box');
const dimensions = [];

// Read phase
boxes.forEach(box => {
dimensions.push([box.offsetWidth, box.offsetHeight]);
});

// Write phase
boxes.forEach((box, i) => {
const [width, height] = dimensions[i];
box.style.width = (width * 2) + 'px';
box.style.height = (height * 2) + 'px';
});

Using will-change Property

1
2
3
4
5
6
7
8
9
/* Hint to the browser that an element will change */
.sidebar {
will-change: transform;
}

/* Remove when animation complete to free up resources */
.sidebar.animation-done {
will-change: auto;
}

Using CSS Containment

1
2
3
4
5
6
7
8
9
/* Isolate elements from rest of the document */
.widget {
contain: content; /* or layout, paint, size, etc. */
}

/* For isolated subtrees */
.comment-section {
contain: strict;
}

Layer Optimization

1
2
3
4
/* Promote to a separate layer only when needed */
.moving-element {
transform: translateZ(0); /* Creates a new compositor layer */
}

JavaScript Optimization

Bundle Optimization

Code Splitting

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// React code splitting with dynamic import
import React, { lazy, Suspense } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
</div>
);
}

Tree Shaking

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Only used functions will be included in the final bundle

// Modern ES module syntax enables tree shaking
export function used() {
console.log('This function is used');
}

export function unused() {
console.log('This function is never imported, so it will be tree-shaken');
}

// In another file
import { used } from './utils';
used(); // Only this function gets included in the bundle

Optimizing Critical JavaScript

1
2
3
4
5
6
7
8
<!-- Inline critical JavaScript -->
<script>
// Critical initialization code
document.querySelector('.main-content').classList.add('visible');
</script>

<!-- Defer non-critical scripts -->
<script src="non-critical.js" defer></script>

Memory Management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Remove event listeners when no longer needed
function setupElement(element) {
const handleClick = () => {
// Handle click
};

element.addEventListener('click', handleClick);

// Return cleanup function
return () => {
element.removeEventListener('click', handleClick);
};
}

// With React hooks
useEffect(() => {
const element = document.getElementById('my-element');
const handleClick = () => {
// Handle click
};

element.addEventListener('click', handleClick);

// Cleanup function
return () => {
element.removeEventListener('click', handleClick);
};
}, []);

Avoiding Memory Leaks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Bad: Unintended closure retains references
function setupObserver() {
const largeData = getLargeData();

const element = document.getElementById('observed');

const observer = new IntersectionObserver(() => {
// This closure captures largeData, preventing it from being garbage collected
console.log('Element visible', largeData.length);
});

observer.observe(element);
}

// Good: Clean up properly
function setupObserver() {
const element = document.getElementById('observed');

const observer = new IntersectionObserver(() => {
console.log('Element visible');
});

observer.observe(element);

// Return cleanup function
return () => {
observer.disconnect();
};
}

Asset Optimization

Image Optimization

1
2
3
4
5
6
7
8
9
10
11
<!-- Use modern formats -->
<picture>
<source type="image/avif" srcset="image.avif">
<source type="image/webp" srcset="image.webp">
<img
src="image.jpg"
alt="Optimized image"
loading="lazy"
decoding="async"
>
</picture>

Font Optimization

1
2
3
4
5
6
7
8
9
10
11
<!-- Preload critical fonts -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- Font display strategies -->
<style>
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap; /* Use system font until custom font is ready */
}
</style>

CSS Optimization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Critical CSS inlined -->
<style>
/* Critical styles for above-the-fold content */
body {
margin: 0;
font-family: system-ui, sans-serif;
}
.hero {
height: 100vh;
background-color: #f5f5f5;
}
</style>

<!-- Non-critical CSS loaded asynchronously -->
<link rel="preload" href="/css/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

Framework-Specific Optimizations

React

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Use React.memo for expensive components
const ExpensiveComponent = React.memo(({ data }) => {
// Render using data
return <div>{/* ... */}</div>;
});

// Use useMemo for expensive calculations
function DataProcessingComponent({ data }) {
const processedData = useMemo(() => {
return expensiveProcessing(data);
}, [data]);

return <div>{/* Use processedData */}</div>;
}

// Use useCallback for stable callbacks
function ParentComponent() {
const [count, setCount] = useState(0);

const handleClick = useCallback(() => {
// Handle click
}, []); // No dependencies = function reference stays the same

return <ChildComponent onClick={handleClick} />;
}

Vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div>
<!-- Use v-show instead of v-if for frequently toggled content -->
<div v-show="isVisible">Frequently toggled content</div>

<!-- Keep v-for items keyed -->
<div v-for="item in items" :key="item.id">{{ item.name }}</div>
</div>
</template>

<script>
export default {
// Avoid expensive computations in computed properties
computed: {
filteredItems() {
return this.items.filter(item => item.isActive);
}
},

// Use functional components for simple components
functional: true,
render(h, { props }) {
return h('div', props.text);
}
}
</script>

Angular

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Use OnPush change detection
@Component({
selector: 'app-item',
template: `<div>{{ item.name }}</div>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ItemComponent {
@Input() item: Item;
}

// Use trackBy with ngFor
@Component({
selector: 'app-list',
template: `
<div *ngFor="let item of items; trackBy: trackById">
{{ item.name }}
</div>
`
})
export class ListComponent {
@Input() items: Item[];

trackById(index: number, item: Item): number {
return item.id;
}
}

Network Optimization

Caching Strategies

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Service Worker with Workbox
workbox.routing.registerRoute(
// Cache CSS files
/\.css$/,
// Use cache but update in the background
new workbox.strategies.StaleWhileRevalidate({
// Use a custom cache for CSS
cacheName: 'css-cache',
})
);

workbox.routing.registerRoute(
// Cache image files
/\.(?:png|jpg|jpeg|svg|gif)$/,
// Use the cache if it's available
new workbox.strategies.CacheFirst({
cacheName: 'image-cache',
plugins: [
new workbox.expiration.Plugin({
// Cache only 50 images
maxEntries: 50,
// Cache for 30 days
maxAgeSeconds: 30 * 24 * 60 * 60,
}),
],
})
);

Resource Hints

1
2
3
4
5
6
7
8
9
10
11
12
<!-- Prefetch likely next page -->
<link rel="prefetch" href="/next-page.html">

<!-- Prerender likely next page -->
<link rel="prerender" href="/almost-certainly-next-page.html">

<!-- Preconnect to origins -->
<link rel="preconnect" href="https://api.example.com">
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>

<!-- DNS prefetch (fallback for browsers that don't support preconnect) -->
<link rel="dns-prefetch" href="https://api.example.com">

Compression

1
2
3
4
5
6
7
8
9
10
// Server-side compression (Node.js example with Express)
const express = require('express');
const compression = require('compression');
const app = express();

// Enable compression
app.use(compression());

// Serve static files
app.use(express.static('public'));

Performance Monitoring

Lighthouse

1
2
3
4
5
# Install Lighthouse CLI
npm install -g lighthouse

# Run audit
lighthouse https://example.com --view

Web Vitals Library

1
2
3
4
5
6
7
8
9
10
11
12
13
import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals';

function sendToAnalytics({ name, delta, id }) {
// Send metrics to your analytics service
console.log(`Metric: ${name} \nValue: ${delta} \nID: ${id}`);
}

// Measure and report Core Web Vitals
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);
getFCP(sendToAnalytics);
getTTFB(sendToAnalytics);

Performance API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Measure custom metrics
performance.mark('start-process');

// Do some work...
processData();

performance.mark('end-process');
performance.measure('process-time', 'start-process', 'end-process');

// Get measurements
const measurements = performance.getEntriesByType('measure');
console.log(measurements);

// Report to analytics
const processTime = measurements[0].duration;
sendToAnalytics('custom-process-time', processTime);

Tooling for Performance

Webpack Optimization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// webpack.config.js
module.exports = {
mode: 'production', // Enables optimizations

optimization: {
moduleIds: 'deterministic',
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// Get the package name
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
return `npm.${packageName.replace('@', '')}`;
},
},
},
},
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
},
},
}),
],
},

// Analyze bundle size
plugins: [
new BundleAnalyzerPlugin(),
],
};

Babel Optimization

1
2
3
4
5
6
7
8
9
10
11
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3,
// Only include polyfills and transforms needed for target browsers
targets: '> 0.25%, not dead',
}],
],
};

PostCSS Optimization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'advanced',
}),
require('postcss-preset-env')({
stage: 3,
features: {
'nesting-rules': true,
},
}),
],
};

Testing Environment Performance

Simulating Network Conditions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Puppeteer example
const puppeteer = require('puppeteer');

async function measurePerformance() {
const browser = await puppeteer.launch();
const page = await browser.newPage();

// Simulate slow 3G network
await page.emulateNetworkConditions({
offline: false,
latency: 150,
downloadThroughput: 1.5 * 1024 * 1024 / 8,
uploadThroughput: 750 * 1024 / 8,
});

// Measure page load time
const response = await page.goto('https://example.com');
const performanceTiming = JSON.parse(
await page.evaluate(() => JSON.stringify(performance.timing))
);

console.log(`Time to first byte: ${performanceTiming.responseStart - performanceTiming.requestStart}ms`);
console.log(`DOM Content Loaded: ${performanceTiming.domContentLoadedEventEnd - performanceTiming.navigationStart}ms`);
console.log(`Load: ${performanceTiming.loadEventEnd - performanceTiming.navigationStart}ms`);

await browser.close();
}

measurePerformance();

User-Centric Performance Testing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Capturing Core Web Vitals with Puppeteer
const puppeteer = require('puppeteer');

async function measureCoreWebVitals() {
const browser = await puppeteer.launch();
const page = await browser.newPage();

// Inject web-vitals library
await page.evaluateOnNewDocument(() => {
window.vitalsData = {};
import('https://unpkg.com/web-vitals').then(({ getCLS, getFID, getLCP }) => {
getCLS(metric => { window.vitalsData.CLS = metric.value; });
getFID(metric => { window.vitalsData.FID = metric.value; });
getLCP(metric => { window.vitalsData.LCP = metric.value; });
});
});

await page.goto('https://example.com');

// Wait for metrics to be collected (adjust timeout as needed)
await page.waitForFunction(() => {
return window.vitalsData.CLS !== undefined &&
window.vitalsData.FID !== undefined &&
window.vitalsData.LCP !== undefined;
}, { timeout: 10000 });

const vitals = await page.evaluate(() => window.vitalsData);

console.log('Core Web Vitals:');
console.log(`CLS: ${vitals.CLS}`);
console.log(`FID: ${vitals.FID}ms`);
console.log(`LCP: ${vitals.LCP}ms`);

await browser.close();
}

measureCoreWebVitals();

Performance Checklist

  • Optimize Core Web Vitals (LCP, FID, CLS, INP)
  • Minimize JavaScript bundle size
  • Remove unused CSS and JavaScript
  • Optimize images (format, size, compression)
  • Implement proper caching strategy
  • Use resource hints (preload, prefetch, preconnect)
  • Implement code splitting and lazy loading
  • Optimize fonts (preload, font-display)
  • Minimize third-party impact
  • Avoid layout thrashing
  • Implement critical CSS
  • Defer non-critical JavaScript
  • Optimize for mobile devices
  • Set up performance monitoring
  • Use service workers for offline capability
  • Implement server-side rendering or static generation where appropriate
  • Optimize server response time
  • Use HTTP/2 or HTTP/3

Learning Resources

  • Web Vitals - Google’s essential metrics for a healthy site
  • MDN Web Performance
  • Lighthouse Performance Scoring
  • High Performance Web Sites by Steve Souders
  • Web Performance in Action by Jeremy Wagner
  • Performance Calendar - Annual web performance articles
  • WebPageTest - Advanced website performance testing

Performance optimization is an ongoing process, not a one-time task. Regular monitoring, testing, and refining are essential to maintain and improve your application’s performance over time.

  • Web Development
  • JavaScript
  • Performance
  • Core Web Vitals
  • Optimization

扫一扫,分享到微信

微信分享二维码
React Fundamentals
Network Protocols for Frontend Developers
目录
  1. 1. Frontend Performance Optimization
    1. 1.1. Core Web Vitals
      1. 1.1.1. Largest Contentful Paint (LCP)
        1. 1.1.1.1. Good LCP Scores
        2. 1.1.1.2. Improving LCP
      2. 1.1.2. First Input Delay (FID)
        1. 1.1.2.1. Good FID Scores
        2. 1.1.2.2. Improving FID
      3. 1.1.3. Cumulative Layout Shift (CLS)
        1. 1.1.3.1. Good CLS Scores
        2. 1.1.3.2. Improving CLS
      4. 1.1.4. Interaction to Next Paint (INP)
        1. 1.1.4.1. Good INP Scores
        2. 1.1.4.2. Improving INP
    2. 1.2. Rendering Performance
      1. 1.2.1. Critical Rendering Path
      2. 1.2.2. Reducing Layout Thrashing
      3. 1.2.3. Using will-change Property
      4. 1.2.4. Using CSS Containment
      5. 1.2.5. Layer Optimization
    3. 1.3. JavaScript Optimization
      1. 1.3.1. Bundle Optimization
        1. 1.3.1.1. Code Splitting
        2. 1.3.1.2. Tree Shaking
      2. 1.3.2. Optimizing Critical JavaScript
      3. 1.3.3. Memory Management
      4. 1.3.4. Avoiding Memory Leaks
    4. 1.4. Asset Optimization
      1. 1.4.1. Image Optimization
      2. 1.4.2. Font Optimization
      3. 1.4.3. CSS Optimization
    5. 1.5. Framework-Specific Optimizations
      1. 1.5.1. React
      2. 1.5.2. Vue
      3. 1.5.3. Angular
    6. 1.6. Network Optimization
      1. 1.6.1. Caching Strategies
      2. 1.6.2. Resource Hints
      3. 1.6.3. Compression
    7. 1.7. Performance Monitoring
      1. 1.7.1. Lighthouse
      2. 1.7.2. Web Vitals Library
      3. 1.7.3. Performance API
    8. 1.8. Tooling for Performance
      1. 1.8.1. Webpack Optimization
      2. 1.8.2. Babel Optimization
      3. 1.8.3. PostCSS Optimization
    9. 1.9. Testing Environment Performance
      1. 1.9.1. Simulating Network Conditions
      2. 1.9.2. User-Centric Performance Testing
    10. 1.10. Performance Checklist
    11. 1.11. Learning Resources

150 篇 | 131.7k
次 | 人
这里自动载入天数这里自动载入时分秒
2022-2025 loong loong | 新南威尔士龙龙号