
前端性能优化是一个系统工程,涉及多个层面。本文将聚焦于常见的性能瓶颈,提供实用的优化方案。
图片资源优化
图片通常是页面加载的主要瓶颈。以下是一些有效的优化方法:
使用现代图片格式如WebP,它通常比JPEG或PNG更小。
img {
width: auto;
height: auto;
image-rendering: -webkit-optimize-contrast;
}
对于复杂的图片,可以考虑使用SVG格式。对于需要缩放的图片,可以使用CSS的object-fit属性。
懒加载是另一种有效的方法,可以延迟非视口图片的加载。
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
// Fallback for browsers without IntersectionObserver
lazyImages.forEach(function(lazyImage) {
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazy");
});
}
});
对于CDN的使用,可以显著提升图片加载速度。
JavaScript优化
JavaScript的加载和执行会影响页面渲染。
代码分割可以将大型JS文件拆分成更小的块,按需加载。
import("./module1.js")
.then((module) => {
module.doSomething();
})
.catch((error) => {
console.error("Error loading module:", error);
});
避免在主线程上执行重型计算,可以使用Web Workers。
if (window.Worker) {
let myWorker = new Worker("worker.js");
myWorker.postMessage({ type: "start", data: largeData });
myWorker.onmessage = function(e) {
console.log("Received message from worker:", e.data);
};
}
使用事件委托可以减少事件处理器的数量。
document.getElementById("container").addEventListener("click", function(event) {
if (event.target.matches(".button")) {
console.log("Button clicked:", event.target.id);
}
});
避免不必要的DOM操作,可以使用DocumentFragment。
let fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
let div = document.createElement("div");
div.textContent = "Item " + i;
fragment.appendChild(div);
}
document.getElementById("container").appendChild(fragment);
CSS优化
CSS的加载和解析也会影响页面渲染。
使用CSS的media queries可以按设备加载不同的样式表。
@media (max-width: 600px) {
body {
background-color: lightblue;
}
}
避免使用深层次的CSS选择器,它们会增加浏览器的计算负担。
使用CSS的will-change属性可以提前告诉浏览器哪些元素会有动画,以便进行优化。
.animate {
will-change: transform;
}
缓存策略
合理的缓存策略可以显著提升加载速度。
使用HTTP缓存头可以控制资源的缓存行为。
Cache-Control: public, max-age=31536000
ETag: "abc123"
对于静态资源,可以使用Service Workers进行缓存和更新。
self.addEventListener("install", function(event) {
event.waitUntil(
caches.open("my-cache").then(function(cache) {
return cache.addAll([
"/index.",
"/styles.css",
"/script.js",
"/image1.png"
]);
})
);
});
self.addEventListener("fetch", function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
对于API请求,可以使用Cache API进行缓存。
caches.match("/api/data").then(function(response) {
if (response) {
return response.json();
} else {
return fetch("/api/data").then(function(networkResponse) {
caches.put("/api/data", networkResponse.clone());
return networkResponse.json();
});
}
});
网络优化
网络优化是提升加载速度的关键。
使用HTTP/2可以提升多资源加载速度。
使用HTTP/3可以减少延迟。
使用CDN可以减少请求的延迟。
使用GZIP或Brotli可以压缩资源大小。
nginx配置示例
http {
gzip on;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
}
使用HTTP/2的服务器推送可以提前加载关键资源。
if (window.HttpPush) {
let pushPromise = window.HttpPush("/styles.css");
pushPromise.then(function(response) {
console.log("Pushed styles.css");
}).catch(function(error) {
console.error("Push failed:", error);
});
}
使用DNS预解析可以减少DNS查找时间。
字体优化
字体资源也会影响加载速度。
使用Web字体格式如WOFF2可以减小字体文件大小。
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}
使用字体子集化可以只加载页面需要的字体字符。
使用字体加载策略可以控制字体的加载时机。
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
font-display: swap;
}
代码分割
代码分割可以将大型JS文件拆分成更小的块,按需加载。
import("./module1.js")
.then((module) => {
module.doSomething();
})
.catch((error) => {
console.error("Error loading module:", error);
});
使用React.lazy和Suspense可以实现组件级别的代码分割。
import React, { Suspense, lazy } from "react";
const LazyComponent = lazy(() => import("./LazyComponent"));
function App() {
return (
My App
<Suspense fallback={Loading...}>
);
}
export default App;
使用Webpack的Dynamic Imports API也可以实现代码分割。
预加载和预连接
使用link标签的rel属性可以进行资源的预加载和预连接。
预加载可以提前加载关键资源,预连接可以提前建立与外部服务的连接。
服务端渲染
服务端渲染可以提升首屏加载速度。
使用Next.js可以实现服务端渲染和静态站点生成。
import { GetServerSideProps } from "next";
export default function Page({ data }) {
return (
{data.title}
{data.content}
);
}
export const getServerSideProps = async () => {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
return { props: { data } };
};
使用Nuxt.js可以实现Vue.js的服务端渲染。
Web Workers
Web Workers可以将重型计算移到后台线程,避免阻塞主线程。
if (window.Worker) {
let myWorker = new Worker("worker.js");
myWorker.postMessage({ type: "start", data: largeData });
myWorker.onmessage = function(e) {
console.log("Received message from worker:", e.data);
};
}
使用Web Workers可以实现复杂的计算任务,而不会影响页面渲染。
Tree Shaking
Tree Shaking可以移除未使用的代码,减小JS文件大小。
使用Webpack的mode设置为production可以启用Tree Shaking。
// webpack配置示例
module.exports = {
mode: "production",
optimization: {
usedExports: true
}
};
使用Rollup或Parcel等打包工具也可以实现Tree Shaking。
HTTP/3
HTTP/3使用QUIC协议可以减少延迟和丢包。
使用QUIC可以提升小对象的加载速度。
Chrome和Firefox已经支持HTTP/3。
资源压缩
资源压缩可以减小资源文件的大小。
使用GZIP或Brotli可以压缩、CSS和JS文件。
nginx配置示例
http {
gzip on;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。