性能优化
多尺寸多分辨率图片
通过 srcset 和 sizes 属性,达到不同屏幕宽度显示不同的图片目的。配合一些图片云服务可以很方便的生成不同尺寸的图片。(多分辨率比如高清屏幕,1个css像素对应多个物理像素)
优先使用webp
可使用 picture 标签来枚举一些格式,优先显示的格式放在前面
图片懒加载
对于不在可视区域的图片延迟加载,可使用 loading="lazy" 属性。或者使用相关库(如react-lazy-load),控制在离可视区域多远时才进行加载。
预连接
在和服务器请求资源时,必须先建立连接。建立一个安全的链接包含一下三步:
- 查找域名并将其解析为 IP 地址
- 建立与服务器的连接
- 对连接进行安全加密
我们可以通过 preconnect 及早的建立连接,通过与重要的第三方来源建立早期连接,可以将加载时间缩短 100-500 毫秒。
<link rel="preconnect" href="https://example.com">
如果一个网页需要连接大量的三方域名,如果都使用 preconnect 的话将会适得其反。preconnect 仅适合在最关键的连接上使用,对于其他的则使用 <link rel=dns-prefetch> 来节省DNS解析时间,这个一般花费 20-120ms。
DNS预连接通过添加如下 <link> 标签在文档的 <head> 部分:
<link rel="dns-prefetch" href="http://example.com">
dns-prefetch 浏览器的支持度下要比 preconnect 要好一点,因此可以作为 preconnect 的备选:
<link rel="preconnect" href="http://example.com">
<link rel="dns-prefetch" href="http://example.com">
对于 JS 的加载还有 defer 和 async 两种异步模式。JS默认模式下会阻塞DOM的渲染,必须等JS加载和执行完后才能做其他的事情。
异步模式不会阻塞DOM的渲染,defer 相对 async 的区别是:defer 资源会在 DOMContentLoaded 之前执行,并且 defer 的加载是有序的,如果强调有序的话使用 defer。
<script src="index.js"></script>
<script async src="index.js"></script>
<script defer src="index.js"></script>
提前加载
使用preload,对一些关键资源进行优先加载:
<link rel="preload" as="image" href="important.png">
<link rel="preload" href="/js/script.js" as="script">
关键图片的预加载对于提升 LCP 比较有用。
响应式图片的preload,imagesrcset和imagesizes同img的srcset和sizes
<img src="wolf.jpg" srcset="wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w" sizes="50vw" alt="A rad wolf">
<link rel="preload" as="image" href="wolf.jpg" imagesrcset="wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w" imagesizes="50vw">
我们也可以使用 fetchpriority 设置为 high 来提升关键资源的优先级,low 来降低其他资源的优先级。(这个属性的兼容性貌似不是很高)
<img src="/images/in_viewport_but_not_important.svg" fetchpriority="high" alt="I'm an unimportant image!">
<link rel="preload" href="/js/script.js" as="script" fetchpriority="high">
<script>
fetch('https://example.com/', {priority: 'high'})
.then(data => {
});
</script>
<iframe src="https://example.com" width="600" height="400" fetchpriority="high"></iframe>
缓存
Next.js SSR优化
- 使用
getStaticProps进行SSG预生成,如果预生成有一点的时效性,可以使用revalidate属性控制。
性能指标
LCP
参考:web.dev/lcp/
简介
最大内容绘制 (LCP) 指标会根据页面首次开始加载的时间点来报告可视区域内可见的最大图像或文本块完成渲染的相对时间。为了提供良好的用户体验,网站应该努力将最大内容绘制控制在2.5 秒或以内。
最大内容绘制考量的元素类型为:
<img>元素- 内嵌在
<svg>元素内的<image>元素 <video>元素(使用封面图像)- 通过
url()函数(而非使用CSS 渐变)加载的带有背景图像的元素 - 包含文本节点或其他行内级文本元素子元素的块级元素。
LCP 主要受四个因素影响:
- 缓慢的服务器响应速度
- JavaScript 和 CSS 渲染阻塞
- 资源加载时间
- 客户端渲染
使用Lighthouse优化
预加载关键资源
如果某个资源被解析和延迟获取,Lighthouse 会显示以下失败的审计:
Preload 是一个声明性的获取请求,它会告诉浏览器尽快请求资源。通过在 HTML 文档头部添加带有 rel="preload" 的 <link> 标签来预加载关键资源:
<link rel="preload" as="style" href="css/style.css">
浏览器会为资源设置更合适的优先级,以便在不推迟 window.onload 事件的情况下尽快下载它。
尽快渲染初始路线
如果存在延迟首次绘制(First Paint,即网站将像素呈现到屏幕的那一刻)的资源,Lighthouse 会发出警告:
为了改进 First Paint,Lighthouse 建议内联关键 JavaScript 并使用 async 推迟其余部分,以及内联首屏使用的关键 CSS。这样可以消除到服务器的往返,从而获取阻塞渲染的资产,提高性能。但是从开发的角度来看,内联代码更难维护,并且无法被浏览器单独缓存。
另一种改进 First Paint 的方法是在服务器端渲染页面的初始 HTML。这会在仍在获取、解析和执行脚本时立即向用户显示内容。但是,这会显着增加 HTML 文件的有效负载,可能会损害 Time to Interactive ,或者影响到应用程序变得可交互并可以响应用户输入所需的时间。
降低应用程序中的 First Paint 并没有固定的单一解决方案。只有在对应用程序利大于弊的情况下,您才应该考虑使用内联样式和服务器端渲染。
预缓存资源
通过充当代理,服务工作进程可直接从缓存中获取资产,而不用在重复访问时从服务器获取。这不仅可以使用户在离线时使用您的应用程序,而且还可以在重复访问时加快页面的加载速度。
使用第三方库来简化生成服务工程进程的过程,除非这些库所无法满足您那些更复杂的缓存需求。例如, Workbox 提供了一组工具,可以让您创建和维护服务工作进程来缓存资产。有关服务工作进程和离线可靠性的更多信息,请参阅可靠性学习路径中的服务工作进程指南。
延迟加载
如果您通过网络发送的数据太多,Lighthouse 会显示审计失败。
这包括所有资产类型,但由于浏览器解析和编译大型 JavaScript 有效负载需要时间,因此尤其消耗尤其严重。 Lighthouse 还会在适当的时候为此提供警告。
要发送仅包含用户最初加载应用程序所需代码的较小 JavaScript 有效负载,请根据需要拆分整个包并延迟加载代码块。
一旦成功拆分数据包,请预加载更重要的代码块。预加载可确保浏览器更快地获取和下载更重要的资源。
除了按需拆分和加载不同的 JavaScript 代码块外,Lighthouse 还提供对延迟加载非关键图像的审计。
如果您在网页上使用了许多图像,请在加载页面时延迟加载所有位于首屏下方或设备视区之外的图像。
工具
- 浏览器各种参数统计,分辨率统计:gs.statcounter.com/
- webp工具,需梯子,developers.google.com/speed/webp/…
- 网站性能测试 webpage test:www.webpagetest.org
- PageSpeed Insights: pagespeed.web.dev/