首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容
在页面渲染的过程,导致加载速度慢的因素可能如下:
通过压缩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文件中,我们将引入压缩和合并后的静态资源文件。
<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中。这样做可以减少网络请求次数和文件大小,提高页面加载速度。
使用适当的图片格式(如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>
</body>
<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 {
// Fallback for browsers that don't support IntersectionObserver
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>
</html>
示例代码使用 IntersectionObserver API 实现图片懒加载,如果浏览器不支持该 API,则会回退到基于滚动事件的实现方式。
具体来说,该示例首先获取所有带有 data-src 属性的图片元素,并将它们保存在一个数组中。然后,如果浏览器支持 IntersectionObserver API,则创建一个 IntersectionObserver 对象,并为每个图片元素添加观察器。当图片元素进入视口时,观察器会将其 data-src 属性值设置为 src 属性值,并移除 data-src 属性。最后,观察器会取消对该图片元素的观察。
如果浏览器不支持 IntersectionObserver API,则会使用一个 lazyLoad 函数,该函数会在滚动、窗口大小调整或设备方向变化时被触发。在该函数中,会遍历所有带有 data-src 属性的图片元素,并检查它们是否在视口中可见。如果是,则将其 data-src 属性值设置为 src 属性值,并移除 data-src 属性。最后,会从数组中删除已经加载的图片元素,并检查数组是否为空。如果为空,则取消事件监听。
JavaScript预加载(Preloading)是一种前端性能优化技术,其核心思想是在用户实际需要某些资源之前,提前将这些资源加载到浏览器缓存中。这样,当用户访问这些资源时,可以直接从本地缓存中获取,从而减少等待时间,提升用户体验。
主要利用的是浏览器缓存。如下面是使用promise的预加载策略:
<script>
//这个代码放在页面加载之前执行
const loadImgAsync = function (path) {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = function () {
resolve(img);
};
img.onerror = function () {
reject(new Error(`Could not load image at ${path}`));
};
img.src = path;
});
};
const img = document.querySelector("#img");
loadImgAsync(
"https://scpic.chinaz.net/files/pic/pic9/202009/apic27858.jpg"
)
.then((res) => {
img.src = res.src;
})
.catch((err) => {
console.log(err);
});
</script>
使用内容分发网络(CDN)来加速静态资源的传输,将资源缓存在离用户较近的服务器上,减少网络延迟。
下面以一个网站为例,说明CDN如何工作:
假设有一个名为www.example.com
的网站,该网站拥有许多静态资源,如图像、CSS文件和JavaScript文件等。这些资源可能存储在网站的主机上,但是由于主机的位置和用户之间的距离不同,因此用户在访问这些资源时可能会遇到网络延迟。
为了解决这个问题,网站所有者可以使用CDN服务。CDN服务通常由多个服务器组成,这些服务器分布在全球各地,每个服务器都缓存了网站的静态资源。当用户请求这些资源时,CDN会将请求路由到最近的服务器,从而减少网络延迟并提高资源加载速度。
例如,当用户从中国访问www.example.com
时,CDN会将用户请求路由到位于中国的服务器。如果该服务器上已经缓存了所需的静态资源,那么用户将立即获得资源。否则,CDN
将从主机上获取资源,并将其缓存到服务器上,以便以后的请求可以更快地获取资源。
总之,使用CDN可以提高网站性能,减少网络延迟,提高用户体验。
一般直接在模板中使用script标签src属性引用。 也可以在项目中配置基础路径。
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/'
}),
// 其他插件...
],
// 其他配置项...
};
缘由
SSR(服务器端渲染)能够提高首屏渲染的原因有以下几点:
可选用框架
前端可以使用一些框架或库来实现服务器端渲染(SSR),下面是几个常用的前端框架:
loading或者骨架屏