First Screen Optimization Techniques for Web Performance
This article explains what first‑screen optimization is and presents ten practical methods—including resource compression, image optimization, asynchronous loading, preloading, CSS/JS optimization, caching strategies, server‑side rendering, CDN acceleration, and delayed loading—complete with detailed Webpack configurations and code examples to improve initial page render speed.
前言
面试官问你首屏优化没有?
什么是
首屏优化是指在网页加载过程中,尽快展示给用户可见的内容,以提高用户体验和页面加载速度。
常用方法
1、压缩和合并资源
通过压缩CSS、JavaScript和HTML等静态资源文件,并将它们合并为较少的文件,可以减少网络请求次数和文件大小,加快页面加载速度。
压缩
以下是一个示例Webpack配置文件,展示如何使用 css-minimizer-webpack-plugin 、 mini-css-extract-plugin 压缩CSS文件和 terser-webpack-plugin 压缩JavaScript文件。
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// 入口文件
entry: './src/index.js',
// 输出文件
output: {
filename: 'bundle.min.js',
path: __dirname + '/dist',
},
// 模块加载器
module: {
rules: [
// 处理CSS文件
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
// 处理JavaScript文件
{
test: /\.js$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
// 插件
plugins: [
new MiniCssExtractPlugin({
filename: 'styles.min.css',
}),
],
// 优化配置
optimization: {
minimizer: [
// 压缩CSS文件
new CssMinimizerPlugin(),
// 压缩JavaScript文件
new TerserPlugin(),
],
},
};合并静态资源
在 index.html 文件中,我们将引入压缩和合并后的静态资源文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React App</title>
<link rel="stylesheet" href="styles.min.css">
</head>
<body>
<div id="root"></div>
<script src="bundle.min.js"></script>
</body>
</html>通过上述代码,我们将压缩和合并后的CSS文件和JavaScript文件引入到了 index.html 中,减少网络请求次数和文件大小,提高页面加载速度。
2、图片优化
使用适当的图片格式(如JPEG、PNG、WebP)和压缩算法,对图片进行优化,减小文件大小,并使用懒加载技术延迟加载非首屏可见的图片。
举例一个懒加载示例:
<!DOCTYPE html>
<html>
<head>
<style>
.image-container {height:200px;width:200px;overflow:hidden;background-color:#eee;}
img {display:block;height:auto;width:100%;}
</style>
</head>
<body>
<div class="image-container">
<img data-src="image.jpg" alt="Image" />
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img[data-src]"));
if ("IntersectionObserver" in window) {
var lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.removeAttribute("data-src");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
var lazyLoad = function() {
lazyImages.forEach(function(lazyImage) {
if (lazyImage.getBoundingClientRect().top <= window.innerHeight &&
lazyImage.getBoundingClientRect().bottom >= 0 &&
getComputedStyle(lazyImage).display !== "none") {
lazyImage.src = lazyImage.dataset.src;
lazyImage.removeAttribute("data-src");
lazyImages = lazyImages.filter(function(image) { return image !== lazyImage; });
if (lazyImages.length === 0) {
document.removeEventListener("scroll", lazyLoad);
window.removeEventListener("resize", lazyLoad);
window.removeEventListener("orientationchange", lazyLoad);
}
}
});
};
document.addEventListener("scroll", lazyLoad);
window.addEventListener("resize", lazyLoad);
window.addEventListener("orientationchange", lazyLoad);
}
});
</script>
</body>
</html>示例代码使用 IntersectionObserver API 实现图片懒加载,如果浏览器不支持则回退到基于滚动事件的实现方式。
3、异步加载
将不影响首屏展示的资源(如统计代码、广告等)使用异步加载方式引入,避免阻塞首屏内容的加载。
可以使用 JavaScript 动态创建 <script> 标签并插入文档,实现异步加载。
示例:
function loadExternalScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.async = true;
script.onload = () => { resolve(); };
script.onerror = () => { reject(new Error(`Failed to load script ${url}`)); };
document.head.appendChild(script);
});
}
// 异步加载统计代码
loadExternalScript('https://example.com/analytics.js')
.then(() => { console.log('Analytics script loaded'); })
.catch(error => { console.error(error); });
// 异步加载广告代码
loadExternalScript('https://example.com/advertisement.js')
.then(() => { console.log('Advertisement script loaded'); })
.catch(error => { console.error(error); });4、预加载关键资源
通过预加载关键资源(如字体文件、重要的 CSS 和 JavaScript 文件),在首屏展示之前提前加载这些资源,加快后续页面加载速度。
示例:
<!DOCTYPE html>
<html>
<head>
<title>预加载关键资源示例</title>
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="styles.css" as="style" crossorigin>
<link rel="preload" href="script.js" as="script" crossorigin>
<style>
/* 首屏样式 */
body {font-family: 'FontName', sans-serif;}
</style>
<link rel="stylesheet" href="styles.css">
<script src="script.js" defer></script>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>5、CSS优化
避免使用过多的 CSS 文件和行内样式,尽量减少 CSS 文件大小,并将 CSS 放在页面头部,以便尽早渲染页面。
<!DOCTYPE html>
<html>
<head>
<title>示例页面</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>欢迎来到示例页面</h1>
<p>这是一个简单的示例页面。</p>
</body>
</html>6、JavaScript优化
将 JavaScript 代码放在页面底部,减少对页面渲染的阻塞,并通过压缩、去除不必要的注释和空格来减小文件体积。
<!DOCTYPE html>
<html>
<head>
<title>JavaScript代码放在页面底部示例</title>
</head>
<body>
<!-- 页面内容 -->
<script src="script.js"></script>
</body>
</html>7、缓存策略
合理设置缓存策略,利用浏览器缓存减少重复加载相同资源的次数,提高页面加载速度。
// 假设我们有一个名为 "api.js" 的模块,用于发送网络请求
// 缓存对象,用于存储已经请求过的数据和过期时间
const cache = {};
// 发送网络请求的函数
async function fetchData(url) {
// 检查缓存中是否存在数据
if (cache[url] && cache[url].expires > Date.now()) {
console.log('从缓存中获取数据:', cache[url].data);
return cache[url].data;
}
// 发送网络请求
const response = await fetch(url);
const data = await response.json();
// 设置缓存有效期为1小时
const expires = Date.now() + 3600000;
// 将数据和过期时间存入缓存
cache[url] = { data, expires };
console.log('从服务器获取数据:', data);
return data;
}
async function getData() {
const url = 'https://api.example.com/data';
try {
const data = await fetchData(url);
console.log('处理数据:', data);
} catch (error) {
console.error('请求失败:', error);
}
}
// 调用获取数据的函数
getData();8、服务端渲染(SSR)
缘由
SSR 能够减少客户端渲染时间、提前获取数据、提升 SEO 并改善用户体验。
可选用框架
Next.js :基于 React 的 SSR 框架,支持自动代码分割、预取和缓存。
Nuxt.js :基于 Vue.js 的 SSR 框架,提供类似功能。
Angular Universal :Angular 官方的 SSR 解决方案。
9、CDN加速
使用内容分发网络(CDN)将静态资源缓存到离用户更近的服务器,减少网络延迟并提升加载速度。
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 其他配置项...
output: {
// 设置输出路径和文件名
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
publicPath: 'https://cdn.example.com/' // 设置 CDN 路径
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 在 HTML 模板中使用 CDN 路径
cdnPath: 'https://cdn.example.com/'
}),
// 其他插件...
],
// 其他配置项...
};10、延迟加载非关键资源
将广告、推荐内容等非关键资源的加载延迟到首屏渲染完成之后,以提升首屏展示速度。
<!DOCTYPE html>
<html>
<head>
<title>延迟加载示例</title>
</head>
<body>
<h1>首屏内容</h1>
<!-- 非关键资源 -->
<div id="ad-container"></div>
<script src="ad.js" defer></script>
<script>
// 首屏渲染完成后执行
window.addEventListener('load', function() {
// 加载广告
var adContainer = document.getElementById('ad-container');
var adScript = document.createElement('script');
adScript.src = 'ad.js';
adContainer.appendChild(adScript);
});
</script>
</body>
</html>最后
你快回答他,说 "我知道!!是...这样!"
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.