Front-end performance optimization: Make page loading as smooth as the fragrance of tea.
Performance optimization is like brewing a good cup of tea—water temperature, timing, and technique must all be just right. Page load speed directly impacts user experience, and every detail, from resource compression to code splitting, can become a culprit for lag. The following practical tips will make your web pages flow as smoothly as tea pouring into a cup.
Prioritizing Resource Loading
Resources on the critical rendering path need priority handling. Use preload
for critical CSS and fonts, and delay non-critical resources with prefetch
:
<!-- Load above-the-fold CSS immediately -->
<link rel="preload" href="critical.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="critical.css"></noscript>
<!-- Lazy-load non-critical images -->
<img src="placeholder.jpg" data-src="hero-image.jpg" loading="lazy" class="lazyload">
Dynamic import in React:
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<HeavyComponent />
</Suspense>
);
}
The Art of Image Optimization
WebP is 30% smaller than JPEG with comparable quality. Use the <picture>
element for graceful degradation:
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Example image">
</picture>
Inline SVG icons to reduce HTTP requests:
<svg viewBox="0 0 24 24" width="24" height="24">
<path d="M12 2L4 12l8 10 8-10z" fill="currentColor"/>
</svg>
JavaScript Execution Optimization
Avoid long tasks blocking the main thread by offloading compute-intensive work to Web Workers:
// main.js
const worker = new Worker('compute.js');
worker.postMessage({data: largeArray});
worker.onmessage = (e) => {
console.log('Result:', e.data);
};
// compute.js
self.onmessage = (e) => {
const result = heavyComputation(e.data);
self.postMessage(result);
};
Event delegation to reduce listener count:
document.getElementById('list').addEventListener('click', (e) => {
if(e.target.matches('.item')) {
handleItemClick(e.target);
}
});
CSS Rendering Magic
Use will-change
to hint browsers about upcoming changes:
.animated-element {
will-change: transform, opacity;
transition: transform 0.3s ease-out;
}
Avoid layout thrashing (forced synchronous layouts):
// Bad practice: Alternating reads/writes trigger multiple reflows
elements.forEach(el => {
const width = el.offsetWidth; // Read
el.style.width = (width + 10) + 'px'; // Write
});
// Good practice: Batch reads/writes
const widths = elements.map(el => el.offsetWidth); // Batch read
widths.forEach((width, i) => {
elements[i].style.width = (width + 10) + 'px'; // Batch write
});
Sophisticated Caching Strategies
Service Worker for offline caching:
// sw.js
const CACHE_NAME = 'v1';
const ASSETS = ['/styles/main.css', '/scripts/app.js'];
self.addEventListener('install', (e) => {
e.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS))
);
});
self.addEventListener('fetch', (e) => {
e.respondWith(
caches.match(e.request)
.then(response => response || fetch(e.request))
);
});
HTTP cache headers (Nginx config example):
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Modern Framework Performance Tips
Vue's v-once
and v-memo
optimizations:
<template>
<!-- Static content renders once -->
<div v-once>{{ staticContent }}</div>
<!-- Skips updates when dependencies don't change -->
<div v-memo="[dependency]">{{ computedContent }}</div>
</template>
React's useMemo
and useCallback
:
function ExpensiveComponent({ items }) {
const processedItems = useMemo(() => {
return items.map(heavyProcessing);
}, [items]);
const handleClick = useCallback(() => {
console.log('Memoized handler');
}, []);
return <ChildComponent items={processedItems} onClick={handleClick} />;
}
Monitoring and Continuous Optimization
Using Performance API for metrics collection:
// Measure FP/FCP
const perfObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.startTime}`);
}
});
perfObserver.observe({ type: 'paint', buffered: true });
// Custom metrics
const start = performance.now();
someOperation();
const duration = performance.now() - start;
Chrome DevTools' Lighthouse panel generates detailed reports. Focus on:
- First Contentful Paint (FCP)
- Largest Contentful Paint (LCP)
- Cumulative Layout Shift (CLS)
- First Input Delay (FID)
Build Tool Optimization
Webpack chunk splitting example:
// webpack.config.js
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
Vite's on-demand loading config:
// vite.config.js
import { splitVendorChunkPlugin } from 'vite'
export default {
plugins: [splitVendorChunkPlugin()],
build: {
rollupOptions: {
output: {
manualChunks: {
'lodash': ['lodash'],
'chartjs': ['chart.js']
}
}
}
}
}
Mobile-Specific Considerations
Touch event optimization (300ms delay fix):
<meta name="viewport" content="width=device-width, initial-scale=1.0">
// Using fastclick library
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
Avoid mobile repaint jank:
/* Enable GPU acceleration */
.transform-element {
transform: translateZ(0);
backface-visibility: hidden;
perspective: 1000px;
}
/* Scroll optimization */
.scroll-container {
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
Balancing Performance and Security
CSP policy impact on performance:
<!-- Allow inline scripts but restrict external resources -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'unsafe-inline' https://cdn.example.com;
style-src 'self' 'unsafe-inline'; img-src * data:;">
Non-blocking third-party script loading:
function loadScript(src, callback) {
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = callback;
document.head.appendChild(script);
}
loadScript('https://analytics.example.com/tracker.js', () => {
initTracker();
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn