Web页面优化专项>Lighthouse>性能分数优化

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Web页面优化专项>Lighthouse>性能分数优化

Lighthouse 简介


Lighthouse 是一个开源的自动化工具,可以用于改进 Web 应用的质量。


Lighthouse 目前已经集成在新版本 Chrome DevTools 中,也可以将其作为一个 Chrome 扩展程序运行,或从命令行运行。


Lighthouse 会针对 Web 页面运行一些自动化测试,生成一个有关页面性能的报告,然后就可以根据测试报告来优化页面。


Lighthouse 测试报告包含五块内容:性能、无障碍、最佳做法、SEO、PWA,我们今天主要是针对性能报告提出优化方案及复现代码。


bVcYomX.webp.jpg


Chrome DevTools 可以调整语言哟,比如说从英文改成中文。

Lighthouse 性能指标


  1. First Contentful Paint

FCP 指首次内容渲染时间,标识网页首次渲染出首个文本、图片(页面上的图像、非白色 <canvas> 元素和 SVG 被视为 DOM 内容。不包括 iframe 内的任何内容)的时间。 FCP 分位图

  1. Time to Interactive

TTI 指可交互时间,标识网页需要多长时间才能提供完整交互功能。我们知道 JS 主线程是单线程的,如果有长 JS 任务是会阻塞页面交


  1. Speed Index

速度指数表明了网页内容的可见填充速度


  1. Total Blocking Time

TBT 指累计阻塞时间,标识网页首次内容渲染 (FCP) 和可交互时间之间的所有超时任务的超时累计时间,按 60FPS 算,时间应该是不超过 16ms
超时任务指任务用时超过 50ms,如果 Lighthouse 检测到一个 70ms 长的任务,则阻塞部分将为 20ms。


  1. Largest Contentful Paint

LCP 指 最大内容绘制,标识网页渲染出最大文本或图片的时间。类似于 First Meaningful Paint(FMP 首次有效绘制)(主要内容对用户可见的时间) 指标,但是 LCP 是一通用固定计算规则

  1. Cumulative Layout ShiftCLS 指累积布局偏移,标识网页可见元素在视口内的移动情况。计算规则


  • 比如说在网上阅读一篇文章,结果页面上的某些内容突然发生改变?文本在毫无预警的情况下移位,导致您找不到先前阅读的位置。
  • 比如正要点击一个链接或一个按钮,但在手指落下的瞬间,诶?链接移位了,结果点到了别的东西!大多数情况下,这些体验只是令人恼火,但在某些情况下,却可能带来真正的破坏(点拒绝结果变成了允许)。
  • 或者想想变态猫?看着是平平无奇,但是操作的时候飞来横祸。


view.webp (10).jpg


LCP、FCP 示例


图片来源:https://web.dev/lcp/#-2

bVcYotz.webp.jpg

bVcYotB.webp.jpg

bVcYotC.webp.jpg

bVcYotE.webp.jpg


Lighthouse 优化建议


建议一:减少未使用的 JavaScript、CSS 代码


bVcYoIz.webp.jpg


手段1:异步。等需要时再加载


名词有很多:懒加载、延时加载、闲时加载、按需加载等等。


  1. 「懒加载」import 异步组件


  1. 比如说我们有一个消息中心模块,内部有用户端和管理端页面。这两个页面应该使用异步组件。因为目的不是发就是收,而且管理端是需要权限才可以看到的。


        b.比如说我们的消息模块,支持 markdown、富文本、docs、xlsx 等等类型,但是一条消息只能显示一个类型,所以我们可以把 DocsView 来封装一下,动态加载组件渲染。


 2.「懒加载」import 异步功能


  1. 比如说我们的表格有导出功能,基于 xlsx 实现。这样一个功能也不是高频功能,所以我们也可以通过 import 来异步载入使用。


  1. 「延时加载」通过手动调整优先级、或者延时器来实现功能。需要注意 CLS 指标,这里需要注意不要造成 CLS 指标异常。


  1. 还是我们消息模块的例子,在 LCP 之前我们不去加载是否有最新消息,等 LCP 之后再去加载。这里对于首屏减少了请求,对于用户的影响也会比较小 (只显示一个红点,用户有红点和无红点的点击效果都是查看消息列表)。


        b.对于关注、点赞、收藏等开关模块需要慎重。因为效果是相反的,本来是关注,结果有可能变成了取消。


手段2:摇树优化 Tree-Shaking


可以将未使用的代码逻辑在编译时删除。


因为 Webpack 4 是默认开启状态,所以我们只说一些限制条件。


  • 只对 ES Module 起作用,对于 commonjs 无效,对于 umd 亦无效。
  • 需要包本身支持才可以。
  • 注意配置 sideEffects ,防止 Css 被优化
  • 需要 build 时才会优化。process.env.NODE_ENV === 'production' 状态


手段3:babel 降低适配版本


设置合理的 .browserslistrc,进行 babel、babel-polyfill 转义。


比如说只支持 Chrome 的后台系统,就不需要转义 IE 系列了,这样可以大大减小体积。


总结&注意事项


  1. css 的优化,也可以依赖异步组件。


  1. 三方库可以考虑使用组件做二次封装。


  1. 正确的区分 v-if 和 v-show,深入研究 el-tabs 实现机制。确保组件并没有被真实的实例化


  1. 可以通过 chrome-devtools 中 coverage 来查看哪些代码没有被执行。
    可以分析具体有哪些代码没有被执行到,我们期望的结果是加载的每一行代码都是有用的。
    可以看到有一个资源一大半代码都没有被用到,这都是浪费。如果带宽是按量付费的人得哭死。

bVcYoT4.webp.jpg


  1. last 2 verions 表示支持所有版本后两位。也包括永远不更新的 IE


建议二:优化体积、消除重复代码


手段1:压缩


  1. 资源服务器开始 Gzip 压缩,设置资源 30D 缓存。然后通过文件名 hash 来更新


  1. CDN 一般来说都会支持压缩和缓存,并且带宽也是比较靠谱的,节点距离用户也比较近。


  1. jsmin、摇树优化等方案。


  1. 注意图片类型。纯色图片 png,复杂图片 jpg,webp 更小。


  1. 注意图片尺寸。尽量不要过大,注意裁图。


手段2:消除重复包。依赖共享


  1. lerna + yarn

常见重复包(axios、ui 库),因为我们好多组件都是基于业务封装(什么叫基于业务封装?内部有逻辑,存在数据调用自动更新,UI 可以直接在业务内使用)。
我们使用了 lerna 来做相同版本共享,我们一般要求使用相同版本。


  1. peerDependencies

因为某些原因,有一些包并不是所有项目都有的,或者说对于版本有强依赖。我们也需要配置 peerDependencies 来让使用方可以安装正确版本的依赖。


  1. externals

部分三方库版本号是 0.xx.x,因为 lerna 是基于首位不为 0 的进行比较是否为相同版本。导致 axios@0.23axios@0.24 不认为是相同版本。
这个时候我们会使用 externals 来强制不打包,让使用方来提供。


  1. 统一构建工具及版本

因为有时候我们会有一些基础包(babelbabel-polyfill),但是各个 cli 版本使用的版本、方式不一样,对于转义处理也是不一致的,为了使用最小的包体积,我们要求相同相同版本的 cliwebpack


手段3:替换包,选择更小的版本


  1. 小包替换大包,按需包替换全量包


  1. momentjs 改为使用 dayjsmomentjs 包只使用 format 大概在 100k 左右,而 dayjs 只有 10k 不到。
    这是因为 momentjs 里面打入了 i18n 语言包。
    所以还有另一个方案就是改成语言按需引入。
  2. 避免 import _ from 'lodash ,而是使用 lodash-es。

建议三:减少重排、减少布局变动、减少 DOM 数量


可以理解为 CLS 指标。


手段1:使用固定宽高


bVcYplx.webp.jpg


一般来说都有固定高度(24*24),我们把它限制在一个范围内。防止因为图片异步加载回来,撑开 dom 后,导致其后数据全部发生变动。


  1. 比如说在文章类页面中,如果有记住上次浏览位置。如何保证用户还能定位到上次位置?如果不使用固定宽高,那么用户有可能看到的内容会一直发现变化。
  2. 比如说在微信聊天页面,如何一直定位在页面最底部?当图片加载完成之后会出现高度变化。


手段2:虚拟化、虚拟列表、墓碑机制、分页加载、懒加载


虚拟列表类似实现一个最差边界方案,我只显示 20 个,这就是我性能最差的时候。不管 100 个、1000 个,我只显示 20 个。


  1. select、table、tree 等长列表注意使用虚拟列表。


  1. 比如说微信聊天,左边的会话列表大家会删除嘛?估计会有几百、几千个,包括单聊、群聊、通知、公众号等等。
    会有几个节点?头像、名称、消息摘要、时间、屏蔽、未读等等,就算会有 10 个标签。10 * 1000 这样就一万个标签了,如果使用虚拟列表,10 * 50 这样也才 500 个标签。
  2. 比如说有一些树节点,层级覆盖下去有可能会在几十万个节点,如果再操作选中之类的逻辑


  1. 异常的 tooltip 节点。


  1. 比如说会提前渲染组件。
  2. 比如说会进行频繁变更。


建议四:降低内存占用、降低 CPU 使用率


手段1:图片懒加载


图片会占用实际内存,导致卡顿。


  1. 注意图片尺寸。尽量不要过大,注意裁图。


  1. 只加载视口的图片。其他图片按需加载,参考文章页面返回上次阅读逻辑功能,如果不按需会导致无法查看图片。


手段2:减少 JS 代码、减少 CSS 代码


参考上面的逻辑就好了。


代码减少,下载、解析、执行的时候当然都会减少呀


建议您减少为解析、编译和执行 JS 而花费的时间。您可能会发现,提供较小的 JS 负载有助于实现此目标。

bVcYpnR.webp.jpg


建议五:降低网络负载、加快用户下载速度


资源下载速度限制条件一般有什么?


  1. 带宽(吞吐)1M小水管
  2. 距离(远近)华北地方内访问、全球访问
  3. 介质(稳定)有线、无线、WiFi、5G、4G


手段1:增加带宽


需要充钱才能解决的问题都不予解决


如果是服务器带宽不够,那么解决办法就是充钱。

如果是用户带宽不够,那么只能好好优化。


手段2:上 CDN


CDN 的关键技术主要有内容存储和分发技术,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。


简单来说就是距离用户近,带宽大,网络畅通不拥塞。


手段3:缩小体积


(同建议一、建议二)


手段4:增加缓存


bVcYpmp.webp.jpg


前端项目一般 html 不缓存,然后资源通过 hash name 来更新。

世界级别的难题:如何让缓存过期和如何让缓存不过期。


建议六:缩短执行时间、缩短执行链路、避免阻塞主线程


手段1:减少主线程工作,优化代码执行速度


  1. 正确使用循环。应该先执行 filter,再执行 map
    因为 filter 之后,数量会变少(随机数,变成一半),两个示例等于 1.5倍 和 2倍 的对比。
    那么有什么办法可以 1 倍出结果吗?(reduce?)

bVcYpgB.webp.jpg


  1. 正确使用循环。如果不使用结果,应该使用 forEach 遍历。


bVcYpha.webp.jpg


  1. 优化嵌套循环。上面的例子充其量就是 N * 2,嵌套循环就会变成 N²。一般出现在树状结构,比如说权限。
    例子采用去重来说明差距


bVcYphu.webp.jpg


  1. 使用 lodash 中的方法来简化数据处理逻辑。
    可以实现代码少、效率高、语义明确。
    Object.entries(treeData).filter(([, v]) => v.level === 0).forEach(([key]) => { 这行代码想做什么?有什么性能上的问题吗?

bVcYpjf.webp.jpg

Object.entries(treeData) 的性能偏差,tree 节点量级是多少?考虑用 lodash 提供的方法,性能会好一点(循环次数变少,3次降成1次)、代码变得更少了(减少了无用的语义)、语义也更加明确了(把对象转换成keyvalue数组,过滤掉有level的,遍历执行逻辑 => 遍历对象)。


手段2:减少串行代码,缩短请求链路


  1. await、async 的乱用


bVcYpjs.webp.jpg


建议七:避免过时的代码


Vue、react 之类框架代码还好,有统一的管理方式。常见的是一些老项目、js、jQuery 项目。


  1. 禁止 document.write
  2. 样式放上面、JS 放下面。不要阻塞 DOM 解析。


总结


优化之路,相辅相成。


  1. 优化加载速度。扩大带宽、缓存、内容分发、减小体积。
  2. 优化体积。减少损耗,减少解析时间。
  3. 优化逻辑。懒加载、异步加载、减少无效损耗、提升执行效率。


项目实战


我提供了一些最简案例在仓库中:Demo 仓库地址,你只需要看例子就可以直接看到问题(然后你可以去优化它)。

相关文章
|
2天前
|
存储
在 Web 中判断页面是不是刷新
【9月更文挑战第10天】在Web开发中,判断页面是否刷新有多种方法:1) 监听`popstate`事件,检测用户是否通过历史记录访问页面;2) 记录并比较页面加载时间戳,若相差极小,则可能为刷新;3) 利用本地存储设置特定值,若该值不存在或不符合预期,则页面可能被刷新。然而,这些方法并非绝对准确。
|
11天前
|
SQL 安全 数据库
Web安全漏洞专项靶场—SQL注入—docker环境—sqli-labs靶场—详细通关指南
Web安全漏洞专项靶场—SQL注入—docker环境—sqli-labs靶场—详细通关指南
40 1
|
14天前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
25 1
|
14天前
|
物联网 C# 智能硬件
智能家居新篇章:WPF与物联网的智慧碰撞——通过MQTT协议连接与控制智能设备,打造现代科技生活的完美体验
【8月更文挑战第31天】物联网(IoT)技术的发展使智能家居设备成为现代家庭的一部分。通过物联网,家用电器和传感器可以互联互通,实现远程控制和状态监测等功能。本文将探讨如何在Windows Presentation Foundation(WPF)应用中集成物联网技术,通过具体示例代码展示其实现过程。文章首先介绍了MQTT协议及其在智能家居中的应用,并详细描述了使用Wi-Fi连接方式的原因。随后,通过安装Paho MQTT客户端库并创建MQTT客户端实例,演示了如何编写一个简单的WPF应用程序来控制智能灯泡。
32 0
|
14天前
|
Java 开发者 JavaScript
Struts 2 开发者的秘籍:隐藏的表单标签库功能,能否成为你下个项目的大杀器?
【8月更文挑战第31天】Struts 2表单标签库是提升Web页面交互体验的神器。它提供丰富的标签,如`&lt;s:textfield&gt;`和`&lt;s:select&gt;`,简化表单元素创建与管理,支持数据验证和动态选项展示。结合示例代码,如创建文本输入框并与Action类属性绑定,显著提升开发效率和用户体验。通过自定义按钮样式等功能,Struts 2表单标签库让开发者更专注于业务逻辑实现。
38 0
|
14天前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
25 0
|
14天前
|
安全 Java 云计算
JSF 应用究竟何去何从?云端部署能否成为其全新突破点?快来一探究竟!
【8月更文挑战第31天】本文介绍了将JavaServer Faces(JSF)应用部署到云平台的过程。首先,根据成本、功能、可靠性和安全性选择合适的云平台。接着,展示了构建简单JSF应用的示例代码。最后,以AWS Elastic Beanstalk为例,详细说明了部署流程。部署至云端可提升应用的可用性、扩展性和安全性。
28 0
|
14天前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
38 0
|
14天前
|
开发者 Java
Play Framework深度解析:依赖注入的神秘力量,如何助力Web应用架构优化?答案即将揭晓!
【8月更文挑战第31天】依赖注入(DI)是现代软件开发的关键技术,用于分离对象创建与依赖关系,提升代码的可维护性和可测试性。Play Framework是一款高性能Java Web框架,内置了基于Google Guice的DI支持。本文探讨Play Framework中DI的最佳实践,包括定义组件、构造函数注入、字段注入以及作用域控制和自定义绑定等高级特性,帮助开发者轻松构建结构清晰、可维护性高的Web应用。
27 0
|
14天前
|
安全 前端开发 PHP
构建与验证表单:传统PHP与Laravel框架的比较分析——探索Web开发中表单处理的优化策略和最佳实践
【8月更文挑战第31天】在 Web 开发中,表单构建与数据验证至关重要。传统 PHP 方法需手动处理 HTML 表单和数据验证,而 Laravel 框架则提供了一种更现代、高效的解决方案。本文通过对比传统 PHP 和 Laravel 的方法,探讨表单构建与验证的最佳实践。Laravel 通过简洁的语法糖、内置的数据过滤和验证机制,显著提升了代码的安全性和可维护性,适用于大型项目或需要快速开发的场景。然而,在追求灵活性的小型项目中,直接使用 PHP 仍是不错的选择。了解两者的优劣,有助于开发者根据项目需求做出最佳决策。
22 0