记一次rax应用用户体验性能优化

2024-02-01 11:20

本文主要是介绍记一次rax应用用户体验性能优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言


对于前端开发攻城狮们来说,性能优化是一个永恒的话题。随着前端需求复杂度的不断升高,在项目中想始终保持着良好的性能也逐渐成为了一个有挑战的事情。本次分享简述我们在 Rax 项目中常用的一些性能优化方式,并将从近期的一个实际业务需求出发,讲述我在 Rax C端应用场景下所遇到性能问题排查时的心路历程。
本次分享的优化内容,主要是指用户滑动屏幕浏览页面过程中所花费的单帧渲染耗时的降低比例。 单帧渲染耗时通过 chrome dev tools 插件以及手淘端app dev tools测得。一般来说浏览器运行帧率为 60hz,因此对于帧率要求非常高的场景如内容输入后的响应、动画等,需要尽可能的将单帧耗时控制在 16.6ms(1s / 60)以内,用户才能完全感知不到系统的卡顿。对于一般性能要求没那么高的应用场景,单帧耗时能达到33.2ms(2s / 60),也能达到一个相对流畅的用户体验。
实际业务现状
接下来我将从近期参与的一个实际业务需求出发,记录下我在这个项目中遇到性能问题时,发现问题、解决问题的心路历程。
从实际业务场景出发,我们发现不少页面在用户滑动浏览页面的过程中存在卡顿,一些情况下卡顿严重,非常影响用户体验,由于多数安卓机的渲染性能不如IOS系统,安卓端的性能问题会尤其明显

那么如何优化这个性能问题?

在 Rax当前的版本中,rax框架使用同步渲染模式(Synchronous Rendering),也就是说,在处理更新时会阻塞整个 UI 线程,直到所有更新完成才会重新渲染视图。这种方式虽然简单易懂,但是在处理大量或复杂数据时存在明显的性能问题,导致应用程序出现卡顿或者无响应等问题。

React18的并发模式(Concurrent Mode),它可以将渲染任务分解成多个小块,并通过 React 的调度器(Scheduler)来优化执行顺序和时间,从而降低了单次渲染所需的计算资源和时间。并发模式可以在渲染过程中及时响应用户的输入和请求,避免出现 UI 卡顿或者无响应的情况,从而提高了整个应用的用户体验。

目前Rax框架在性能优化上虽然不及react18,但仍然有非常好的应用渲染性能基础,站在了巨人的肩膀上,我们所能做的,便是在不添乱的前提下,帮助Rax更快、更高效的完成遍历渲染的过程,使更新链路尽可能的短的走完

排查流程

通过安卓手淘扫码观察app dev tools的性能分析,每帧普遍在 700ms以上,最严重的长达 1847ms

观察发现最耗时的任务为一个叫appear的函数执行,appear函数出现在trackerLink组件中,是曝光方法,也就是说,每当一个标签需要进行曝光,那么当这个元素出现在浏览器视口,就会触发此appear方法,随着一次又一次的需求迭代,需要曝光的点越来越多,导致每一次元素重新出现在适口,都会有大量的appear方法调用,消耗了大量的性能,在安卓系统性能不够优秀的机型上,用户体验表现就会卡顿。

当我们滑动页面时,由于大量元素需要进行曝光操作,appear函数长时间执行,对于用户来讲,这段时间界面是卡死且无法交互的。

如果我们把这个例子中的appear函数类比成Rax的更新过程:即setState触发了一次更新,而这次更新耗时非常久,比如1800ms。那么在这1800ms的时间内界面是卡死的,用户无法进行交互,非常影响用户的使用体验。

优化思路

雪中送炭

擒贼先擒王,首先解决最影响性能的,怎么让appear方法的执行不影响主线程的渲染?

1.接入react18?

成本太高。pass

2.使用requestIdleCallback来控制appear方法的执行不影响主线程?

requestIdleCallback 会将任务安排在浏览器的空闲时期执行。在当前页面的生命周期内,也不能保证 requestIdleCallback 中的任务一定会执行。如果浏览器长时间忙于处理高优先级任务,低优先级的空闲回调可能会被推迟,直到有足够的空闲时间来执行它们。如果这种情况一直持续,那么这些任务可能会被无限期地推迟。pass

3.如果任务是关键性的,需要在特定时间内一定要执行,那么使用 setTimeout可能是更好的选择。setTimeout这个API提供了更可靠的方式来计划任务的执行,即使它们没有 requestIdleCallback 提供的执行时机那样灵活。

setTimeout将同步任务变为异步任务,当需要trackertLink组件需要曝光时,将曝光函数异步执行,不阻塞影响主线程渲染,提高用户体验性。

改动TrackerLink组件:

// needAsyncSending控制埋点曝光异步进行,不阻塞主线程
if (needAsyncSending) {const sendExpTimer = setTimeout(() => {recordExp();clearTimeout(sendExpTimer);}, 0)
} else {recordExp();
}

优化后:

我们可以看到,当trakcerLink组件异步调用曝光方法时,每帧渲染时间大幅缩减,效果明显,每帧最糟糕的情况从1800ms降低至每帧最糟糕的情况200ms左右,

锦上添花

通过异步发送曝光埋点解决了最大头的性能问题,用户滑动页面时已经不会有明显的延时和滑不动,但是任然有部分顿挫感,由于无法使用react app dev tools工具观察组件的渲染情况,我们使用console.log来判断哪些组件一直在重新渲染,发现在滚动过程中,航班报价列表和报价卡片一直在重新渲染,

但是业务场景下,此种渲染是不必要的,当没有重新发起请求时,是不需要一直重新渲染ota报价卡片

避免 State 的不必要更新

一些业务场景下,不需要一直更新setState,找到不必要的setState,避免这些更新

防止父组件重新渲染重新声明方法导致子组件不必要的重新渲染

纯函数组件使用 Memo 包裹,纯函数组件的function类型的prop使用useCallback包裹

 ===========>>>>>

最终优化效果:

可以看到最终性能分析得到的数据没有明显卡顿的地方,很多帧也达到了16.7ms的理想状态

这篇关于记一次rax应用用户体验性能优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/667126

相关文章

线程池ThreadPoolExecutor应用过程

《线程池ThreadPoolExecutor应用过程》:本文主要介绍如何使用ThreadPoolExecutor创建线程池,包括其构造方法、常用方法、参数校验以及如何选择合适的拒绝策略,文章还讨论... 目录ThreadPoolExecutor构造说明及常用方法为什么强制要求使用ThreadPoolExec

mysql_mcp_server部署及应用实践案例

《mysql_mcp_server部署及应用实践案例》文章介绍了在CentOS7.5环境下部署MySQL_mcp_server的步骤,包括服务安装、配置和启动,还提供了一个基于Dify工作流的应用案例... 目录mysql_mcp_server部署及应用案例1. 服务安装1.1. 下载源码1.2. 创建独立

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南

《SpringBoot基于JWT优化SpringSecurity无状态登录实战指南》本文介绍如何使用JWT优化SpringSecurity实现无状态登录,提高接口安全性,并通过实际操作步骤... 目录Spring Boot 实战:基于 JWT 优化 Spring Security 无状态登录一、先搞懂:为什

Nginx内置变量应用场景分析

《Nginx内置变量应用场景分析》Nginx内置变量速查表,涵盖请求URI、客户端信息、服务器信息、文件路径、响应与性能等类别,这篇文章给大家介绍Nginx内置变量应用场景分析,感兴趣的朋友跟随小编一... 目录1. Nginx 内置变量速查表2. 核心变量详解与应用场景3. 实际应用举例4. 注意事项Ng

CPython与PyPy解释器架构的性能测试结果对比

《CPython与PyPy解释器架构的性能测试结果对比》Python解释器的选择对应用程序性能有着决定性影响,CPython以其稳定性和丰富的生态系统著称;而PyPy作为基于JIT(即时编译)技术的替... 目录引言python解释器架构概述CPython架构解析PyPy架构解析架构对比可视化性能基准测试测

Java中的随机数生成案例从范围字符串到动态区间应用

《Java中的随机数生成案例从范围字符串到动态区间应用》本文介绍了在Java中生成随机数的多种方法,并通过两个案例解析如何根据业务需求生成特定范围的随机数,本文通过两个实际案例详细介绍如何在java中... 目录Java中的随机数生成:从范围字符串到动态区间应用引言目录1. Java中的随机数生成基础基本随

Java JAR 启动内存参数配置指南(从基础设置到性能优化)

《JavaJAR启动内存参数配置指南(从基础设置到性能优化)》在启动Java可执行JAR文件时,合理配置JVM内存参数是保障应用稳定性和性能的关键,本文将系统讲解如何通过命令行参数、环境变量等方式... 目录一、核心内存参数详解1.1 堆内存配置1.2 元空间配置(MetASPace)1.3 线程栈配置1.

Spring Boot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)

《SpringBoot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)》本文将以一个实际案例(用户管理系统)为例,详细解析SpringBoot中Co... 目录引言:为什么学习Spring Boot分层架构?第一部分:Spring Boot的整体架构1.1

利用Python操作Word文档页码的实际应用

《利用Python操作Word文档页码的实际应用》在撰写长篇文档时,经常需要将文档分成多个节,每个节都需要单独的页码,下面:本文主要介绍利用Python操作Word文档页码的相关资料,文中通过代码... 目录需求:文档详情:要求:该程序的功能是:总结需求:一次性处理24个文档的页码。文档详情:1、每个