Comprehensive performance analysis with Lighthouse
Introduction to Lighthouse
Lighthouse is an open-source automated tool developed by Google to improve web page quality. It can audit various aspects of a webpage, including performance, accessibility, progressive web apps, and SEO. Run via Chrome extensions, Chrome DevTools, or the command line, Lighthouse generates a detailed report with scores for each metric and improvement suggestions.
Performance Metrics Breakdown
Lighthouse's performance score is based on multiple key metrics, each reflecting different aspects of user experience:
-
First Contentful Paint (FCP) Measures the time from when the page starts loading to when any part of the page content is rendered on the screen. For users, this is the first feedback they perceive about the page loading.
// Use PerformanceObserver to monitor FCP const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.name === 'first-contentful-paint') { console.log('FCP:', entry.startTime); observer.disconnect(); } } }); observer.observe({type: 'paint', buffered: true});
-
Largest Contentful Paint (LCP) Measures when the largest content element in the viewport becomes visible. This typically corresponds to when the page's main content finishes loading.
-
First Input Delay (FID) Measures the time from when a user first interacts with the page to when the browser can actually respond to that interaction.
-
Cumulative Layout Shift (CLS) Measures the visual stability of a page during loading, quantifying unexpected layout shifts.
-
Speed Index Measures how quickly the page content is visually populated.
Performance Optimization Practices
Optimizing Resource Loading
-
Code Splitting and Lazy Loading Use dynamic imports to split code and load modules only when needed:
// Dynamic import example document.getElementById('btn').addEventListener('click', async () => { const module = await import('./expensiveModule.js'); module.doSomething(); });
For resources like images, use lazy loading:
<img src="placeholder.jpg" data-src="actual-image.jpg" loading="lazy" alt="Example image">
-
Preloading Critical Resources Use
<link rel="preload">
to load critical resources early:<link rel="preload" href="critical.css" as="style"> <link rel="preload" href="main.js" as="script">
Optimizing JavaScript Execution
-
Reducing Main Thread Work Break long-running tasks into smaller chunks:
function processInChunks(array, chunkSize, callback) { let index = 0; function nextChunk() { const chunk = array.slice(index, index + chunkSize); if (chunk.length === 0) return; callback(chunk); index += chunkSize; requestIdleCallback(nextChunk); } nextChunk(); }
-
Using Web Workers Move computation-intensive tasks to Web Workers:
// Main thread const worker = new Worker('worker.js'); worker.postMessage(data); worker.onmessage = (e) => { console.log('Result:', e.data); }; // worker.js self.onmessage = (e) => { const result = heavyComputation(e.data); self.postMessage(result); };
Optimizing CSS
-
Reducing Critical CSS Extract and inline CSS required for above-the-fold rendering:
<style> /* Critical CSS */ .header, .hero { ... } </style>
-
Avoiding CSS @import @import blocks parallel loading; use multiple
<link>
tags instead.
Cache Strategy Optimization
Server-Side Caching
Set appropriate HTTP cache headers:
Cache-Control: public, max-age=31536000, immutable
Client-Side Caching
Implement offline caching with Service Worker:
// service-worker.js
const CACHE_NAME = 'v1';
const ASSETS = [
'/',
'/styles/main.css',
'/scripts/app.js'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Rendering Performance Optimization
Reducing Repaints and Reflows
-
Using transform and opacity for Animations These properties don't trigger layout or paint:
.animate { transition: transform 0.3s ease; } .animate:hover { transform: scale(1.1); }
-
Using will-change to Hint the Browser Inform the browser in advance about elements that will change:
.will-change { will-change: transform, opacity; }
Virtual Scrolling
Implement virtual scrolling for long lists:
class VirtualScroll {
constructor(container, items, itemHeight, renderItem) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;
this.renderItem = renderItem;
this.visibleCount = Math.ceil(container.clientHeight / itemHeight);
this.startIndex = 0;
container.style.position = 'relative';
this.content = document.createElement('div');
this.content.style.height = `${items.length * itemHeight}px`;
container.appendChild(this.content);
this.render();
container.addEventListener('scroll', () => this.handleScroll());
}
render() {
const endIndex = Math.min(this.startIndex + this.visibleCount, this.items.length);
let html = '';
for (let i = this.startIndex; i < endIndex; i++) {
html += this.renderItem(this.items[i], i);
}
this.content.innerHTML = html;
this.content.style.transform = `translateY(${this.startIndex * this.itemHeight}px)`;
}
handleScroll() {
const scrollTop = this.container.scrollTop;
const newStartIndex = Math.floor(scrollTop / this.itemHeight);
if (newStartIndex !== this.startIndex) {
this.startIndex = newStartIndex;
this.render();
}
}
}
Monitoring and Continuous Optimization
Using Lighthouse CI
Integrate Lighthouse CI into the build process:
# .github/workflows/lighthouse.yml
name: Lighthouse
on: [push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm install
- run: npm run build
- uses: treosh/lighthouse-ci-action@v8
with:
urls: |
http://localhost:3000
budgetPath: ./lighthouse-budget.json
Performance Budgets
Create a performance budget file:
{
"ci": {
"collect": {
"numberOfRuns": 3,
"url": ["http://localhost:3000"]
},
"assert": {
"assertions": {
"first-contentful-paint": ["error", {"maxNumericValue": 2000}],
"largest-contentful-paint": ["error", {"maxNumericValue": 4000}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
"interactive": ["error", {"maxNumericValue": 5000}]
}
}
}
}
Advanced Optimization Techniques
Using the PRPL Pattern
PRPL (Push, Render, Pre-cache, Lazy-load) is a performance optimization pattern:
- Push critical resources
- Render the initial route
- Pre-cache remaining routes
- Lazy-load non-critical resources
Server Push
Use HTTP/2 server push:
Link: </styles/main.css>; rel=preload; as=style
Using Brotli Compression
Configure the server to use Brotli compression:
# nginx configuration
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;
Common Issues and Solutions
CLS Issues
Problem: Page elements shift unexpectedly during loading.
Solutions:
- Set width and height attributes for images and videos
- Reserve space for ads
- Avoid inserting new content above existing content
<img src="image.jpg" width="300" height="200" alt="Example">
LCP Issues
Problem: Main content loads too slowly.
Solutions:
- Preload LCP elements
- Use
<link rel="preconnect">
to establish early connections - Optimize server response time
<link rel="preconnect" href="https://example.com">
<link rel="preload" as="image" href="hero-image.jpg">
TTI Issues
Problem: Page takes too long to become interactive.
Solutions:
- Code splitting
- Reduce third-party scripts
- Defer non-critical JavaScript
// Defer loading non-critical scripts
window.addEventListener('load', () => {
const script = document.createElement('script');
script.src = 'non-critical.js';
document.body.appendChild(script);
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:移动设备兼容性优化