鸿蒙性能优化之响应优化

181 阅读4分钟

一、简介

  响应是指应用在运行中,用户做出一个行为,程序做出一系列运算,最终界面发生变化的过程。响应优化的目的是程序能够尽可能快的给出结果。响应越快,发生卡顿或者卡死的概率就越低。但响应慢并不意味着发生卡顿或者卡死的概率就高,如果我们把耗时操作放到子线程,此时不会发生卡顿或者卡死,只是响应慢。主线程执行耗时操作,响应会慢,发生卡顿或者卡死的概率就会高。响应分为响应时延和完成时延,如下图所示,响应时延的起点是点击离手,终点是页面首次发生变化。完成时延的起点是点击离手,终点是页面加载完成,用户可以稳定的使用程序。建议响应时延应<=100毫秒,完成时延≤900毫秒。 image.png

二、分析工具

  Profiler是DevEco Studio提供的性能调优工具,通过录制应用运行过程中的关键数据,从而识别卡顿丢帧、耗时长等问题的原因所在。在鸿蒙性能优化之卡顿优化文章中已经介绍了如何使用Profile。如何定位原因:分析主进程泳道,观察是否有耗时长的函数阻塞主线程;是否有超长耗时单帧。如果有长段的ExecuteJs 可以查看具体的调用栈或火焰图,定位耗时函数;如果是FlushLayoutTask阶段耗时,就需要结合UI组件树去分析,布局是否合理,是否有优化空间。

2、1 有长段的ExecuteJs

  如下图所示,存在长段的ExecuteJs,说明存在耗时函数。 image.png   选中ArkTS Callstack,打开火焰图,双击定位到耗时代码。 image.png   也可以不打开火焰图,如下图所示,选中ArkTS Callstack,关闭火焰图,可以看到ArkTS侧一些方法的耗时,优先分析耗时最长的调用栈(program除外,program代表程序执行进入纯Native代码阶段,该阶段无Ark TS代码执行,也无Ark TS调用Native或者Native调用Ark TS情况,需要切换到Callstack泳道看具体的调用栈信息,一般很难通过这里分析出有效的信息)。 image.png

2、2 ArkUI Component泳道分析组件绘制耗时

  ArkUI Component泳道记录了自定义组件以及系统组件的绘制次数、耗时等信息,重点关注相对于其他组件耗时比较久的组件。
image.png   然后可以在详情Details中使用下图中被框选的按钮过滤目标组件,查看组件在刷新过程中不同阶段的耗时情况。结合函数调用栈与ArkUI Inspector工具定位目标组件绘制耗时过长的具体原因。 image.png

2、3 H:Animator泳道分析动画时长

  请求网络都会向用户展示“加载中”的状态,直到数据加载完成。可以通过H:Animator泳道,看出动画耗时。 image.png

三、常见响应优化方案

3、1 把网络请求放到子线程

  由于ArkTS单线程EventLoop特性,其异步调用的执行时机会被延迟到同步逻辑后。我们将H网络请求接口放到异步函数时,网络请求会被UI绘制阻塞,网络请求等待第一帧UI绘制结束才开始,如果页面首帧较复杂,则会导致该时长严重增加。更严重的是,异步仍然是在主线程中执行,应用启动的时候,需要请求很多服务端接口,主线程既要绘制UI,又要请求大量的服务端接口,主线程负担太重,大概率会出现卡顿。

3、2 避免在页面子组件中发起网络请求

  由于ArkUI组件的创建基于组件树结构,存在先后顺序。我们在子组件中发起网络请求,该请求需要等待其前面的组件创建完成才会发起,如果前面组件创建耗时较长,也会导致该请求被严重阻塞。

3、3 布局优化

  组件嵌套过深、冗余刷新等都会导致响应变慢,解决方案可查看布局优化

3、4 动态导入

  动态导入允许应用程序在运行时按照实际需求去加载相关模块。在某些条件满足时再加载特定模块,可以减少初始化导入的加载时间和资源消耗,有助于提高应用程序的内存性能和响应速度。具体使用查看《动态导入》

3、5 多线程并发

  系统提供了多线程并发能力,利用TaskPool执行简单并行任务,利用Worker完成周期类耗时操作。多线程并发能够避免阻塞主线程,提升应用的响应速度。

3、6 LazyForEach懒加载

  使用LazyForEach懒加载替换ForEach,避免像ForEach那样一次性初始化和加载所有元素,从而使首帧绘制时创建列表元素时间大大减少,提升响应性能表现。