BI 数据可视化平台建设(3)—首页性能提升实践

作者: vivo 互联网大数据团队- Wang Lei

本文是vivo互联网大数据团队《BI 数据可视化平台建设》系列文章第3篇。

随着越来越多代码的堆积,平台的运行加载性能也在逐步下降,在不同程度上极大地影响了用户体验,从而导致用户流失。本文就是从这样的一个背景出发,通过对BI数据可视化平台的一系列的性能优化实践,给大家系统性阐述首页性能优化的核心策略,并探讨在日常开发中如何实现长效性能保障。

往期系列文章:

  1. BI 数据可视化平台建设(1)—交叉表组件演变实战

  2. BI 数据可视化平台建设(2)—筛选器组件升级实践

文章太长?1分钟看图抓住核心观点👇

图片

一、背景

随着业务的拓展和用户数量的激增,平台经历了多个周期的快速迭代,整体功能场景也越发复杂的。在快速迭代的过程中,我们很容易忽略平台的性能,到了某一个节点,猛地发现,随着越来越多代码的堆积,平台的运行加载性能也在逐步下降,在不同程度上极大地影响了用户体验,从而导致用户流失。本文就是从这样的一个背景出发,通过对BI数据可视化平台的一系列的性能优化实践,给大家分享一下如何提升首页性能的思路,并且让我们在日常开发中,如何持续保持高性能,而不是又一次回过头来优化性能。本文主要给大家介绍一平台在进行首页性能提升的一些实践经验。

二、了解性能指标

2.1 用户体验核心指标

衡量一个 Web 页面的体验和质量有非常多的指标,根据页面加载流程可以将指标分成三大类:

  • 文档加载相关(TTFB、DCL等)

  • 内容呈现相关(LCP、FCP、FMP 等)

  • 交互响应相关(INP、FPS 等)

针对这么多的性能指标,Google 提出了网站用户体验的三大核心指标 (LCP INP CLS),分别用来衡量用户感知的加载速度、量化网页首次互交互的感受、衡量网页视觉的稳定性:

图片

图片来源:https://web.dev/

2.2 平台度量指标

但是在实际规划平台性能度量体系时,我们可以根据自身的业务和需求进行自定义,针对数据可视化平台来说,我们更看重用户感知的加载速度,如何让用户快速看到数据可视化内容是我们首页性能优化的关键,因此我们性能指标主要以文档加载和内容呈现为主,这里我们以 TTFB、FCP、LCP 作为我们首页性能的度量指标,它们涵盖了网络请求到页面主要内容加载的过程:

网络请求过程(网络响应衡量指标 TTFB):

图片

TTFB 主要指的是以下请求阶段耗时的总和:

  • 重定向时间

  • Service Worker 启动时间(如果有)

  • DNS 查找

  • 连接和 TLS 协商

  • 请求,直到响应的第一个字节到达

页面主要内容加载过程(内容呈现衡量指标 FCP、LCP):

图片

图片来源:https://web.dev/

  • TTFB(Time to First Byte ):

它主要测量的是在网络请求阶段中,从请求资源到响应的第一个字节到达所经过的时间,这有助于识别 Web 服务器因速度过慢而无法响应请求。由于 TTFB 发生在指标 FCP(First Contentful Paint ) 和 LCP(Largest Contentful Paint)之前,因此希望服务器能够快速地响应导航请求。一般来说,大多数网站都应尽量将 TTFB 控制在 0.8秒 以内,且超过75%以上PV 达到该范围。

图片

图片来源:https://web.dev/

  • FCP(First Contentful Paint):

它用于标记网页加载过程中用户可以在屏幕上看到的第一个元素所用的时间。元素主要是指文本、图片(包括背景图片)、SVG 或 Canvas。可以用于衡量用户感知的加载速度。为了提供良好的用户体验,网站的 FCP 最好不要超过 1.8 秒,且确保超过75%以上PV 达到该范围。

图片

图片来源:https://web.dev/

  • LCP(Largest Contentful Paint):

它用于标记网页加载过程中加载了网页主要内容的时间点。可以用于衡量用户感知的加载速度,也是Google 提出的度量用户体验的三大核心指标之一。为了提供良好的用户体验,网站的 LCP 最好控制在 2.5 秒 以内,且确保超过75%以上PV 达到该范围。

图片

图片来源:https://web.dev/

三、首页性能现状

**背景:**性能问题主要是由于前期开发人力有限、功能快速迭代等原因,导致代码质量和可维护性较差,积累下的技术债务。

(1)平台性能指标分析:LCP (首屏平均耗时) 高达3.3s,远高于Google LCP衡量的标准(2.5s)。

图片

(2)通过Lighthouse工具进行性能分析,性能得分较低,各项性能指标都处于不及格的水平。

图片

四、分析性能问题

4.1 通过Network面板分析

图片

从Network面板上,可以分析得出加载过程中存在以下几类问题:

  • 入口文件体积太大,加载耗时长,阻塞其他资源加载

  • 低优先级资源阻塞了高优先级资源加载

  • 微前端子应用等非首屏依赖资源没有进行异步加载

  • 网络传输协议还处于HTTP1.1,传输效率低

  • 接口请求传输的数据体过大,存在大量冗余数据

4.2 通过Performance面板分析

图片

从 Performance 面板上,可以分析得出加载过程中存在以下几类问题:

  • FPS 长时间出现红色条形,表示帧速率下降得太低,可能出现动画延迟卡顿等问题

  • CPU 资源占用率过高,可能出现性能问题

  • 主线程存在多个 Long Task(长任务),阻塞了页面加载渲染

4.3 通过Lighthouse工具分析

图片

通过 Lighthouse 工具,可以分析得出加载过程中存在以下的问题:

  • 大量 Long Task 阻塞了主线程工作

  • 存在阻塞渲染的低优先级资源

  • DOM节点数过多,增加了内存占用,样式计算用时延长,并产生高昂的布局重排成本

  • 图片资源不是最优压缩效果的格式

  • 存在大量未使用的CSS和JS文件代码

五、优化实践

5.1 优化方向 (时间和空间)

通过上述的问题分析,我们可以分析出资源加载渲染耗时 以及浏览器性能资源占有 都有可能导致页面卡顿缓慢,影响用户体验,因此可以从耗时和资源占用两方面来进行性能优化,也可以理解成时间和空间的优化。

5.2 时间优化 (网络耗时、加载耗时、渲染耗时等)

(1)网络传输耗时优化

网络传输耗时优化主要可以从 缓存策略、传输协议、资源预加载预解析、CDN 等几个方向进行。本次优化主要是通过网络传输升级、资源预加载、请求性能优化等方面来讲解一下。

  • 网络传输协议升级,由 HTTP/1.1 升级至 HTTP/2.0 版本,通过 HTTP/2.0 多路复用的特性解决了请求并发数限制的问题,同时二进制传输和头部压缩等特性也提高了网络传输的效率。

  • 删除资源预加载(Preload),减少首页非关键资源的预加载处理。通过加载瀑布流可以看到,这里提前加载了多个非首屏关键资源的字体文件,且文件体积高达 1.8MB,阻塞了首屏关键资源的加载解析。所以我们需要根据资源的优先级,合理的使用 Preload(预加载)和 Prefetch(预解析)。

  • 请求性能优化,降低请求响应耗时。通过Network面板可以看到,首页依赖的主要接口返回的数据体在没压缩前高达 3.1 MB,这里我们对请求内容进行了分析,通过异步请求、减少非关键的冗余数据等处理将传输数据体积降低到了 500KB 内。除了减少数据传输量,我们还可以通过请求合并,利用缓存等减少通信次数来进行请求性能优化。

(2)资源加载耗时优化

资源加载耗时优化可以从 代码压缩、代码分包、组件、工具库、ICON等按需加载等几个方向进行。主要是通过优化体积来减少资源加载耗时,从而提升首屏性能。

  • 首先通过 webpack-bundle-analyzer 插件对包体积进行分析,可以看到 chunk-vendors.js 文件体积较大,同时还存在依赖嵌套等问题,导致资源加载缓慢。本次优化我们通过代码分包、资源按需加载,图片格式优化等措施,减少了资源体积, chunk-vendors.js 文件也从 2.3MB 降低到 480KB。下面我们通过几个具体示例进行讲解:

    对 Echarts 、Ant-Design-Vue-1.x ICON等UI工具库进行按需加载。

    // 优化前 在入口文件进行全量的同步加载
    import * as echarts from ‘echarts/core’;
    import { XXXChart } from ‘echarts/charts’;
    import { XXXComponent } from ‘echarts/components’;
    import { CanvasRenderer } from ‘echarts/renderers’;

    echarts.use([XXXChart, XXXComponent, CanvasRenderer]);

    // 优化后 根据使用场景进行按需加载
    async function initEcharts(chartType){
    const echarts = await import(‘echarts/core’);
    const { XXXChart} = await import(‘echarts/charts’);
    const { XXXComponent } = await import(‘echarts/components’);
    const { CanvasRenderer } = await import(‘echarts/renderers’);
    echarts.use([XXXChart, XXXComponent, CanvasRenderer]);
    }

由于历史需求迭代原因,我们对 Ant-Design-Vue-1.x 进行了二次定制开发,这也导致了ICON全量引入,我们这里使用的方案是重定向到本地文件来进行控制 ,使用 alias 将 @ant-design/icons/lib/dist 指向项目中的 antdIcon.js,然后在 antdIcon.js 文件中按需导出即可,通过按需加载,ICON引入体积从 500K+ 降低到 30K+

// vue.config.js alias配置
resolve: {alias: {'@ant-design/icons/lib/dist$': path.resolve(\_\_dirname, './src/plugins/antdIcons.js'),}
}// src/plugins/antdIcons.js
export { default as CheckCircleOutline } from '@ant-design/icons/lib/outline/CheckCircleOutline';
export { default as CheckCircleFill } from '@ant-design/icons/lib/fill/CheckCircleFill';
  • 检查删除冗余依赖,避免重复npm包引入;随着平台长期的发展迭代,或多或少都会存在冗余的 mf、npm 资源,同时我们在对微前端子应用的包体积进行分析时,发现子应用通过 npm 引入的Echarts,而主应用本身也引入相同的库,相对于引入了2 遍 Echarts,这个时候我们改造了子应用的依赖引入方式,通过传参的方式将Echarts实例传递给子应用,避免重复引入和加载相同资源。

    //主应用 通过props传递依赖
    import { start, loadMicroApp, prefetchApps } from ‘qiankun’;

    export default {
    name: ‘MicroWidgetReact’,
    methods: {
    async loadMicroApp(){
    const echarts=awaitthis.echarts = await this.echarts=awaitthis.initEcharts();
    this.microApp = loadMicroApp({
    name: `xxx`,
    props: {
    …props,
    $echarts: $echarts,
    },
    });
    },
    },
    };

    //子应用配置 externals 并且外链依赖加上 ignore 属性(这是自定义的属性,非标准属性)

图片

5.3 空间优化 (CPU 占用、内存占用、本地缓存等)

我们在做性能优化的时候,很多情况下都会依赖时间换空间、或者空间换时间等方式,这里需要根据项目的实际情况做出取舍,选择相对合适的一种方案去进行优化。资源占用常见的优化方式包括:

  • 代码优化:精简和优化 JavaScript 和 CSS 代码,避免使用过多的循环和递归操作,减少对 CPU 的占用。

  • 避免内存泄漏:定期检查并优化内存使用,避免出现内存泄漏问题,可以使用浏览器的开发者工具进行内存分析。

  • 图片懒加载:延迟加载图片,只有当图片进入可视区域时再加载,减少内存占用。

  • 数据本地存储:使用浏览器提供的本地存储功能(如LocalStorage或IndexedDB),将一些数据缓存到本地,减少对网络请求的依赖,提高性能。

  • 使用 Web Workers:将一些耗时的任务放到 Web Workers 中执行,减轻主线程的负担,从而减少 CPU 占用。

  • 使用服务端渲染:使用服务端渲染技术,减少客户端的计算压力,提高页面加载速度。

  • 使用资源压缩:对 JavaScript、CSS、图片等资源进行压缩,减小文件大小,降低网络传输和内存占用。

本次我们主要使用了 Web Workers 和 数据解绑 (Object.freeze) 等方式进行空间优化,减少了CPU和内存的占用。通过 Web Workers 将需要复杂计算任务放到 Worker 线程,避免阻塞其他首页渲染任务,释放主线程资源,实现单线程到多线程。但是这里要注意,过多的使用 Web Workers 有时候反而会导致资源的过度占用,因为 Web Workers 本身也会占用一定的内存资源,而 Workers 之间的通信和数据同步也可能会带来复杂性和性能开销,特别是在大规模的并发任务处理时,所以我们需要根据场景合理使用。

六、优化前后对比

整体性能提升 292%:

图片

优化后的加载效果对比:

图片

七、性能监控

为了保证平台在后续的迭代过程中,持续保持高性能,我们引入Chrome 开源的 web-vitals 库,结合自研的运行时性能监控埋点(卡顿、崩溃),以及平台的数据可视化能力,实现对前端整体性能的监控。并利用了平台的数据监控预警能力,通过对不同指标的配置告警服务,增加性能指标相关的告警,在性能指标发生异动时,及时发现问题,优化性能,保障了用户使用体验。

图片

八、总结

上面讲了那么多优化方法,都是针对当前项目进行的针对性优化 ,所以我们进行优化时,需要根据具体情况和需求,结合不同的优化策略来达到最佳的性能优化效果。前端性能优化是一个重要的主题,它涉及到许多方面,包括页面加载速度、交互响应时间、资源利用效率等。但不管什么样的优化方式,他们的核心思路都是一致的,因为在用户能看到页面,并且与之交互之前,都是有固定的步骤的,所以优化的核心思路就是:**尽可能去掉一些关键步骤、尽可能提前一些重要步骤、尽可能优化某个具体步骤。**比如 SSR 相比于 CSR,用户能更快的看到页面,就是去掉了「下载入口index.html,下载并执行 CSS、JS,请求接口」这几个关键步骤,比如上面说的对高优先级资源进行预加载就是提前一些重要步骤,再比如说通过web workers 避免 JS 执行时产生 Long Task就是优化某个具体步骤。以上就是本次性能优化实践的所有内容,希望能对你有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89665.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Python的毕业设计选题管理系统设计与实现

基于Python的毕业设计选题管理系统设计与实现摘要本论文详细阐述了一个基于Python的毕业设计选题管理系统的设计与实现过程。该系统采用了Python的Tkinter库构建图形用户界面,使用SQLite数据库存储数据,实现了高校毕业设计选题过程中的教师出题、学生选题…

如何在HTML5页面中嵌入视频

在HTML5中嵌入视频主要使用<video>标签&#xff0c;这是一种简单且标准的方式。以下是详细步骤和示例&#xff1a; 基础实现 <!DOCTYPE html> <html> <head><title>视频嵌入示例</title> </head> <body><!-- 基础视频播放器…

java操作Excel两种方式EasyExcel 和POI

一、POI1.引入依赖<!-- 03 xls--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.9</version> </dependency><!-- 07 xlsx --> <dependency><groupId>org.a…

Openlayers 面试题及答案180道(141-160)

《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。 前后端面试题-专栏总目录 文章目录 一、本文面试题目录 141. 如何在生产环境中优…

LangChain面试内容整理-知识点24:实战案例:智能助手 Agent 构建

本案例讲述如何用LangChain构建一个结合多个工具的智能助手 Agent。智能助手需要理解用户复杂请求,通过调用不同工具(如搜索、计算、查数据库等)执行多步推理,再给出答案。LangChain的Agent框架非常适合这种场景。 构建步骤: 确定需求和选择Agent类型:假设我们要一个能上…

【MATLAB例程】Taylor算法用于TOA(到达时间)的三维标签位置解算,可自适应基站数量。附下载链接

本文给出自适应锚点&#xff08;基站&#xff09;的Taylor算法解算TOA&#xff08;到达时间&#xff09;的MATLAB代码。参考论文&#xff1a;《基于Taylor-Chan算法的改进UWB室内三维定位方法》中的Taylor算法来解算TOA的复现程序&#xff08;MATLAB&#xff09;。 文章目录运行…

Eclipse代码折叠增强插件的安装与使用

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;Eclipse作为Java开发者的IDE&#xff0c;提供包括代码折叠在内的多种功能&#xff0c;便于管理与阅读代码。本文介绍的“com.cb.eclipse.folding_1.0.6.jar”插件能够进一步增强Eclipse的代码折叠能力。安装后&…

Python day18

浙大疏锦行 python day 18. 内容&#xff1a; 昨天学习了聚类算法的一些基本内容&#xff0c;今天继续学习相关知识分析簇的特征和相关含义&#xff08;使用可视化来进行分析&#xff0c;也可以使用ai&#xff09; 代码&#xff1a; shap.initjs() # 初始化 SHAP 解释器 ex…

WPS文档中心及文档中台远程命令执行漏洞

【严重】WPS文档中心及文档中台远程命令执行漏洞 漏洞描述 WPS文档中心是面向个人和企业的云端文档存储与管理平台&#xff0c;WPS文档中台是为企业提供的集成化文档协同与流程管理解决方案&#xff0c;强调API对接与业务系统整合。 在2024年5月之前通过docker私有化部署的版…

WPF 加载和显示 GIF 图片的完整指南

WPF 加载和显示 GIF 图片的完整指南 在 WPF 中加载和显示 GIF 图片需要一些特殊处理&#xff0c;因为 WPF 的 Image 控件默认不支持动画 GIF。 解决方案一&#xff1a;使用 WpfAnimatedGif 库&#xff08;推荐&#xff09; 这是最简单且功能最完整的方法。 实现步骤&#xff1a…

Node.js GET/POST请求详解

Node.js GET/POST请求详解 引言 Node.js作为一种基于Chrome V8引擎的JavaScript运行环境&#xff0c;以其高性能、非阻塞I/O模型和轻量级等特点&#xff0c;在服务器端开发中得到了广泛应用。本文将详细介绍Node.js中GET和POST请求的处理方法&#xff0c;帮助开发者更好地理解和…

C++string类(2)

3.string类对象的访问及遍历操作函数名称功能说明operator[] &#xff08;重 点&#xff09;返回pos位置的字符&#xff0c;const string类对象调用beginendbegin获取第一个字符的迭代器 end获取最后一个字符下一个位置的迭代器rbeginrendrbegin获取最后一个字符的迭代器 ren…

SQLShift:一款异构数据库存储过程迁移工具

SQLShift 是一款专注于解决企业级数据库迁移难题的智能 SQL 方言转换平台&#xff0c;尤其擅长异构数据库存储过程的自动化迁移。 SQLShift 工具深度融合了 AI 与 SQL 语法专家模型&#xff0c;可以大幅提升迁移效率并降低人工适配风险。 功能特性 多源多目标&#xff1a;目前…

学习设计模式《十八》——备忘录模式

一、基础概念 备忘录模式的本质是【保存和恢复内部状态】。 备忘录模式的思考序号备忘录模式的思考说明1保存是手段&#xff0c;恢复才是目的标准的备忘录模式保存数据的手段是通过内存缓存&#xff1b;广义的备忘录模式实现的时候&#xff0c;可以采用离线存储的方式&#xff…

HOT100——排序篇Leetcode215. 数组中的第K个最大元素

文章目录题目&#xff1a;Leetcode215. 数组中的第K个最大元素原题链接思路1代码1思路2代码2题目&#xff1a;Leetcode215. 数组中的第K个最大元素 原题链接 数组中的第K个最大元素 思路1 排序 排序后返回倒数第k个数 代码1 思路2 使用priority_queue&#xff0c;大根堆&#x…

三维重建一: 相机几何

参考这位大佬&#xff1a;https://zhuanlan.zhihu.com/p/458000359 一. 基本的投影模型 正如上面所说&#xff0c;相机是一个将三维物体投影为二维图像的设备。 对于小孔相机&#xff0c;或者薄透镜相机来说&#xff0c;基础投影的数学模型可以表达为 我们把这个过程表达在笛…

mysql 字符集不一致导致索引失效问题

mysql 字符集不一致导致索引失效问题 问题&#xff1a; 两张表&#xff0c;同一个字段&#xff0c;由于字符集不一致&#xff0c;导致虽然都有索引&#xff0c;在关联查询时&#xff0c;索引失效身份表 identity_info &#xff0c;查询索引信息 show index from identity_info …

Linux内核设计与实现 - 第6章 内核数据结构

目录1. 链表 (Linked Lists)2. 队列 (Queues)3. 映射 (Maps)4. 二叉树 (Binary Trees)5. 位图 (Bitmaps)6. 其他数据结构性能考量1. 链表 (Linked Lists) 单向链表 vs 双向链表 struct list_head 标准实现内核链表API&#xff1a;LIST_HEAD(), list_add(), list_del() 环形链表…

十五、K8s可观测能力:日志收集

十五、K8s可观测能力&#xff1a;日志收集 文章目录十五、K8s可观测能力&#xff1a;日志收集1、云原生日志框架-ECK介绍1.1 什么是ECK&#xff1f;1.2 ECK核心资源&#xff1a;1.3 生产级日志收集架构2、日志收集-ECK2.1 集群规划2.2 ECK 安装2.3 一键部署高可用 ES 集群2.4 一…

微服务变更?自动化测试利器Parasoft SOAtest修复快、准、稳!

微服务架构凭借灵活和可扩展的优势越来越普及&#xff0c;但随之而来的变更也成了开发团队的“心头大患”。服务之间依赖复杂&#xff0c;接口改来改去&#xff0c;不仅让开发更费劲&#xff0c;还容易导致测试用例失效、测试效率下降&#xff0c;甚至埋下系统不稳的隐患。 自…