首屏优化你被问过没有?
点击关注公众号,“技术干货”及时达!
前言面试官问你首屏优化没有?
什么是首屏优化是指在网页加载过程中,尽快展示给用户可见的内容,以提高用户体验和页面加载速度。
常用方法1、压缩和合并资源通过压缩CSS、JavaScript和HTML等静态资源文件,并将它们合并为较少的文件,可以减少网络请求次数和文件大小,加快页面加载速度。
压缩以下是一个示例Webpack配置文件,展示如何使用css-minimizer-webpack-plugin、mini-css-extract-plugin压缩CSS文件和terser-webpack-plugin压缩JavaScript文件。
constCssMinimizerPlugin=require('css-minimizer-webpack-plugin');
constTerserPlugin=require('terser-webpack-plugin');
constMiniCssExtractPlugin=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:[
newMiniCssExtractPlugin({
filename:'styles.min.css',
}),
],
//优化配置
optimization:{
minimizer:[
//压缩CSS文件
newCssMinimizerPlugin(),
//压缩JavaScript文件
newTerserPlugin(),
],
},
};
合并静态资源在index.html文件中,我们将引入压缩和合并后的静态资源文件。
!DOCTYPEhtml
html
head
metacharset="UTF-8"
titleReactApp/title
linkrel="stylesheet"href="styles.min.css"
/head
body
divid="root"/div
scriptsrc="bundle.min.js"/script
/body
/html
通过上述代码,我们将压缩和合并后的CSS文件和JavaScript文件引入到了index.html中。这样做可以减少网络请求次数和文件大小,提高页面加载速度。
2、图片优化使用适当的图片格式(如JPEG、PNG、WebP)和压缩算法,对图片进行优化,减小图片文件大小,提高加载速度。同时,可以使用懒加载技术,延迟加载非首屏可见区域的图片,减少首屏的加载时间。
举例一个懒加载示例
!DOCTYPEhtml
html
head
style
.image-container{
height:200px;
width:200px;
overflow:hidden;
background-color:#eee;
}
img{
display:block;
height:auto;
width:100%;
}
/style
/head
body
divclass="image-container"
imgsrc="image.jpg"alt="Image"/
/div
/body
script
document.addEventListener("DOMContentLoaded",function(){
varlazyImages=[].slice.call(document.querySelectorAll("img[src]"));
if("IntersectionObserver"inwindow){
varlazyImageObserver=newIntersectionObserver(function(entries,observer){
entries.forEach(function(entry){
if(entry.isIntersecting){
varlazyImage=entry.target;
lazyImage.src=lazyImage.dataset.src;
lazyImage.removeAttribute("src");
lazyImageObserver.unobserve(lazyImage);
}
lazyImages.forEach(function(lazyImage){
lazyImageObserver.observe(lazyImage);
}else{
//Fallbackforbrowsersthatdon'tsupportIntersectionObserver
varlazyLoad=function(){
lazyImages.forEach(function(lazyImage){
if(lazyImage.getBoundingClientRect().top=window.innerHeightlazyImage.getBoundingClientRect().bottom=0getComputedStyle(lazyImage).display!=="none"){
lazyImage.src=lazyImage.dataset.src;
lazyImage.removeAttribute("src");
lazyImages=lazyImages.filter(function(image){
returnimage!==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,则会回退到基于滚动事件的实现方式。
具体来说,该示例首先获取所有带有 src 属性的图片元素,并将它们保存在一个数组中。然后,如果浏览器支持 IntersectionObserver API,则创建一个 IntersectionObserver 对象,并为每个图片元素添加观察器。当图片元素进入视口时,观察器会将其 src 属性值设置为 src 属性值,并移除 src 属性。最后,观察器会取消对该图片元素的观察。
如果浏览器不支持 IntersectionObserver API,则会使用一个 lazyLoad 函数,该函数会在滚动、窗口大小调整或设备方向变化时被触发。在该函数中,会遍历所有带有 src 属性的图片元素,并检查它们是否在视口中可见。如果是,则将其 src 属性值设置为 src 属性值,并移除 src 属性。最后,会从数组中删除已经加载的图片元素,并检查数组是否为空。如果为空,则取消事件监听。
3、异步加载将不影响首屏展示的资源(如统计代码、广告等)使用异步加载方式引入,避免阻塞首屏内容的加载。
可以使用JavaScript的动态脚本加载技术。通过动态创建script标签,并将其插入到文档中,可以实现异步加载资源而不阻塞首屏内容的加载。
举个示例:
functionloadExternalScript(url){
returnnewPromise((resolve,reject)={
constscript=document.createElement('script');
script.src=
script.async=true;
script.onload=()={
resolve();
script.onerror=()={
reject(newError(`Failedtoloadscript${url}`));
document.head.appendChild(script);
}
//异步加载统计代码
loadExternalScript('https://example.com/analytics.js')
.then(()={
//统计代码加载完成后执行的逻辑
console.log('Analyticsscriptloaded');
})
.catch((error)={
console.error(error);
//异步加载广告代码
loadExternalScript('https://example.com/advertisement.js')
.then(()={
//广告代码加载完成后执行的逻辑
console.log('Advertisementscriptloaded');
})
.catch((error)={
console.error(error);
在上面的代码中,loadExternalScript()函数用于动态加载外部脚本。通过将async属性设置为true,确保脚本以异步方式加载,不会阻塞其他资源的加载。然后,我们可以在then()方法中执行相应的逻辑,以响应脚本加载完成的事件。
4、预加载关键资源通过预加载关键资源(如字体文件、重要的CSS和JavaScript文件等),可以在首屏展示之前提前加载这些资源,加快后续页面加载的速度。
要实现预加载关键资源,可以使用HTML中的link和script标签的rel属性来指定资源的加载方式。
举个示例,演示如何预加载字体文件、CSS和JavaScript文件:
!DOCTYPEhtml
html
head
title预加载关键资源示例/title
linkrel="preload"href="font.woff2"as="font"type="font/woff2"crossorigin
linkrel="preload"href="styles.css"as="style"crossorigin
linkrel="preload"href="script.js"as="script"crossorigin
style
/*首屏样式*/
body{
font-family:'FontName',sans-serif;
}
/style
linkrel="stylesheet"href="styles.css"
scriptsrc="script.js"defer/script
/head
body
!--页面内容--
/body
/html
在上述示例中,我们使用了link标签来预加载字体文件、CSS和script标签来预加载JavaScript文件。具体解释如下:
link标签用于预加载字体文件。href属性指定字体文件的URL,as属性设置为"font",表示该资源是字体文件,type属性指定资源的MIME类型,crossorigin属性用于处理跨域请求。同样地,我们使用link标签预加载CSS文件。as属性设置为"style",表示该资源是样式表。最后,我们使用script标签预加载JavaScript文件。as属性设置为"script",表示该资源是脚本文件,defer属性用于延迟脚本的执行。通过以上代码,浏览器在解析HTML时会提前加载这些关键资源,以加快后续页面加载的速度。
5、CSS优化避免使用过多的CSS文件和行内样式,尽量减少CSS文件的大小。另外,可以将CSS放在页面头部,以便尽早渲染页面。
!DOCTYPEhtml
html
head
title示例页面/title
linkrel="stylesheet"href="styles.css"
/head
body
h1欢迎来到示例页面/h1
p这是一个简单的示例页面。/p
/body
/html
这样,浏览器在加载页面时会先加载CSS文件,并根据CSS规则渲染页面,从而提高页面的加载速度和性能。
另外,还可以避免使用行内样式,因为它会增加HTML文件的大小,使得页面加载更慢。如果必须使用行内样式,也应该尽量减少其数量和大小,以便提高页面性能。
6、JavaScript优化将JavaScript代码放在页面底部,以减少对页面渲染的阻塞。另外,可以通过代码压缩、去除不必要的注释和空格等方式来减小JavaScript文件的大小。
!DOCTYPEhtml
html
head
titleJavaScript代码放在页面底部示例/title
/head
body
!--页面内容--
scriptsrc="script.js"/script
/body
/html
示例中,将script标签放在了body标签的最后。这样做可以让浏览器在加载完页面主要内容后再加载JavaScript文件,从而减少对页面渲染的阻塞。
7、缓存策略合理设置缓存策略,利用浏览器缓存来减少重复加载相同资源的次数,提高页面加载速度。
//假设我们有一个名为"api.js"的模块,用于发送网络请求
//缓存对象,用于存储已经请求过的数据和过期时间
constcache=
//发送网络请求的函数
asyncfunctionfetchData(url){
//检查缓存中是否存在数据
if(cache[url]cache[url].expiresDate.now()){
console.log('从缓存中获取数据:',cache[url].data);
returncache[url].data;
}
//发送网络请求
constresponse=awaitfetch(url);
constdata=awaitresponse.json();
//设置缓存有效期为1小时
constexpires=Date.now()+3600000;
//将数据和过期时间存入缓存
cache[url]={data,expires
console.log('从服务器获取数据:',data);
returndata;
}
//在页面中使用fetchData函数来获取数据
asyncfunctiongetData(){
consturl='https://api.example.com/data';
try{
constdata=awaitfetchData(url);
//处理数据
console.log('处理数据:',data);
}catch(error){
console.error('请求失败:',error);
}
}
//调用获取数据的函数
getData();
示例中,定义了一个 fetchData 函数来发送网络请求,并使用一个名为 cache 的对象用于存储已经请求过的数据和过期时间。
当调用 fetchData 函数时,它首先检查缓存中是否已经存在对应 URL 的数据和过期时间。如果存在且有效,则直接从缓存中获取数据,并返回。否则,则发送网络请求获取数据,并将数据与有效期时间戳存入缓存中。
在调用 getData 函数时,它会调用 fetchData 函数来获取数据,并对返回的数据进行处理。
通过这样的缓存策略,当多次调用 getData 函数时,如果 URL 相同,那么后续的请求会直接从缓存中获取数据,而不需要再次发送网络请求。这样可以减少重复加载相同数据的次数,提高页面加载速度和用户体验。
8、服务端渲染(SSR)缘由SSR(服务器端渲染)能够提高首屏渲染的原因有以下几点:
减少客户端渲染时间:在传统的客户端渲染中,浏览器需要下载HTML文件,然后执行JavaScript代码来生成并填充页面内容。而在SSR中,服务器会在响应请求时直接生成完整的HTML页面,并包含所需的数据。这样,浏览器只需要下载已经渲染好的HTML,减少了客户端渲染的时间。提前获取数据:在客户端渲染中,通常需要通过异步请求获取数据,然后再进行页面渲染。而在SSR中,服务器会在渲染过程中获取所需的数据,并将数据直接注入到HTML中。这样可以避免客户端请求数据的延迟,加快了首屏渲染的速度。更好的SEO:由于搜索引擎爬虫更容易解析和索引静态HTML页面,使用SSR可以提供更好的SEO效果。因为在SSR中,服务器返回的是已经渲染好的HTML页面,而不是由JavaScript生成的动态内容。这使得搜索引擎可以更好地理解和索引网页内容,提高了网站在搜索结果中的可见性。更好的用户体验:由于SSR能够更快地呈现出首屏内容,用户可以更快地看到页面的基本结构和内容,减少了等待时间,提升了用户体验。可选用框架前端可以使用一些框架或库来实现服务器端渲染(SSR),下面是几个常用的前端框架:
Next.js:Next.js是一个基于React的SSR框架。它提供了简单的API和约定,使得构建SSR应用变得更加容易。Next.js支持自动代码分割、预取和缓存,以提高性能。它还提供了静态导出功能,可以将应用程序预渲染为静态HTML文件。Nuxt.js:Nuxt.js是一个基于Vue.js的SSR框架。它提供了类似于Next.js的功能,可以帮助开发者快速构建Vue.js应用的SSR版本。Nuxt.js支持自动路由、代码分割和服务端数据获取等特性。Angular Universal:Angular Universal是Angular官方提供的SSR解决方案。它允许在服务器上预渲染Angular应用,以提供更好的性能和SEO效果。Angular Universal可以与Angular CLI集成,方便开发者进行构建和部署。9、CDN加速使用内容分发网络(CDN)来加速静态资源的传输,将资源缓存在离用户较近的服务器上,减少网络延迟。
下面以一个网站为例,说明CDN如何工作:
假设有一个名为 www.example.com 的网站,该网站拥有许多静态资源,如图像、CSS文件和JavaScript文件等。这些资源可能存储在网站的主机上,但是由于主机的位置和用户之间的距离不同,因此用户在访问这些资源时可能会遇到网络延迟。
为了解决这个问题,网站所有者可以使用CDN服务。CDN服务通常由多个服务器组成,这些服务器分布在全球各地,每个服务器都缓存了网站的静态资源。当用户请求这些资源时,CDN会将请求路由到最近的服务器,从而减少网络延迟并提高资源加载速度。
例如,当用户从中国访问 www.example.com 时,CDN会将用户请求路由到位于中国的服务器。如果该服务器上已经缓存了所需的静态资源,那么用户将立即获得资源。否则,CDN将从主机上获取资源,并将其缓存到服务器上,以便以后的请求可以更快地获取资源。
总之,使用CDN可以提高网站性能,减少网络延迟,提高用户体验。
一般直接在模板中使用script标签src属性引用。
也可以在项目中配置基础路径
constwebpack=require('webpack');
constHtmlWebpackPlugin=require('html-webpack-plugin');
module.exports={
//其他配置项...
output:{
//设置输出路径和文件名
path:path.resolve(__dirname,'dist'),
filename:'[name].[contenthash].js',
publicPath:'https://cdn.example.com/'//设置CDN路径
},
plugins:[
newHtmlWebpackPlugin({
template:'./src/index.html',
//在HTML模板中使用CDN路径
cdnPath:'https://cdn.example.com/'
}),
//其他插件...
],
//其他配置项...
};
10、延迟加载非关键资源将非关键资源(如广告、推荐内容等)的加载延迟到首屏渲染完成之后,以提高首屏展示速度。
!DOCTYPEhtml
html
head
title延迟加载示例/title
/head
body
h1首屏内容/h1
!--非关键资源--
divid="ad-container"/div
scriptsrc="ad.js"defer/script
script
//首屏渲染完成后执行
window.addEventListener('load',function(){
//加载广告
varadContainer=document.getElementById('ad-container');
varadScript=document.createElement('script');
adScript.src='ad.js';
adContainer.appendChild(adScript);
/script
/body
/html
最后你快回答他,说"我知道!!是...这样!"
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线