当前位置: 首页 > article >正文

HarmonyOS开发实战( Beta5版)不要使用函数/方法作为复用组件的入参规范实践

概述

在滑动场景下,常常会对同一类自定义组件的实例进行频繁的创建与销毁。此时可以考虑通过组件复用减少频繁创建与销毁的能耗。组件复用时,可能存在许多影响组件复用效率的操作,本篇文章将重点介绍如何通过组件复用四板斧提升复用性能。

 组件复用:

  • 减少组件复用的嵌套层级,如果在复用的自定义组件中再嵌套自定义组件,会存在节点构造的开销,且需要在每个嵌套的子组件中的aboutToReuse方法中实现数据的刷新,造成耗时。
  • 优化状态管理,精准控制组件刷新范围,在复用的场景下,需要控制状态变量的刷新范围,避免扩大刷新范围,降低组件复用的效率。
  • 使用reuseId标记不同结构的组件构成,复用组件嵌套结构会变更的场景,如:使用if else结构来控制组件的创建,会造成组件树结构的大幅变动,降低组件复用的效率。需使用reuseId标记不同的组件结构,提升复用性能。
  • 不要使用函数/方法作为复用组件的入参,复用时会触发组件的构造,如果函数入参中存在耗时操作,会影响复用性能。

组件复用原理机制

组件复用机制图

避免使用函数/方法作为复用组件创建时的入参

由于在组件复用的场景下,每次复用都需要重新创建组件关联的数据对象,导致重复执行入参中的函数来获取入参结果。如果函数中存在耗时操作,会严重影响性能。正反例如下:GitCode - 全球开发者的开源社区,开源代码托管平台

反例:

@Entry
@Component
struct withFuncParam {
  aboutToAppear(): void {
    getFriendMomentFromRawfile();
  }
  // 真实场景的函数中可能存在未知的耗时操作逻辑,此处用循环函数模拟耗时操作
  countAndReturn(): number {
    let temp: number = 0;
    for (let index = 0; index < 100000; index++) {
      temp += index;
    }
    return temp;
  }

  build() {
    Column() {
      TopBar()
      List({ space: ListConstants.LIST_SPACE }) {
        LazyForEach(momentData, (moment: FriendMoment) => {
          ListItem() {
            OneMoment({
              moment: moment,
              sum: this.countAndReturn()
            })
          }
        }, (moment: FriendMoment) => moment.id)
      }
      .cachedCount(Constants.CACHED_COUNT) 
    }
  }
}

@Reusable
@Component
export struct OneMoment {
  @Prop moment: FriendMoment;
  @State sum: number = 0;

  aboutToReuse(params: Record<string, Object>): void {
    this.sum = params.sum as number;
  }

  build() {
    Column() {
      ...
      Text(`${this.moment.userName} (${this.moment.id} / ${this.sum})`)
      ...
    }
  }
}

上述反例的操作中,复用的子组件参数sum是通过耗时函数生成。该函数在每次组件复用时都需要执行,会造成性能问题,甚至是列表滑动过程中的卡顿丢帧现象。

优化前,aboutToReuse中需要重复执行入参中的函数来获取入参结果,导致耗时较长为4ms。

FuncParam

正例:

@Entry
@Component
struct withFuncParam {
  @State sum: number = 0;
    
  aboutToAppear(): void {
    getFriendMomentFromRawfile();
    // 执行该异步函数
    this.countAndRecord();
  }
  // 真实场景的函数中可能存在未知的耗时操作逻辑,此处用循环函数模拟耗时操作
  async countAndRecord() {
    let temp: number = 0;
    for (let index = 0; index < 100000; index++) {
      temp += index;
    }
    // 将结果放入状态变量中
    this.sum = temp;
  }

  build() {
    Column() {
      TopBar()
      List({ space: ListConstants.LIST_SPACE }) {
        LazyForEach(momentData, (moment: FriendMoment) => {
          ListItem() {
            // 子组件的传参通过状态变量进行
            OneMoment({
              moment: moment,
              sum: this.sum
            })
          }
        }, (moment: FriendMoment) => moment.id)
      }
      .cachedCount(Constants.CACHED_COUNT) 
    }
  }
}

@Reusable
@Component
export struct OneMoment {
  @Prop moment: FriendMoment;
  @State sum: number = 0;

  aboutToReuse(params: Record<string, Object>): void {
    this.sum = params.sum as number;
  }

  build() {
    Column() {
      ...
      Text(`${this.moment.userName} (${this.moment.id} / ${this.sum})`)
      ...
    }
  }
}

上述正例的操作中,通过耗时函数countAndRecord生成的结果不变,可以将其放到页面初始渲染时执行一次,将结果赋值给this.sum。在复用组件的参数传递时,通过this.sum来进行。

优化效果

针对列表滑动场景,单个列表项中的一个Text组件,需要依赖复用组件创建时的入参,反例中入参直接传入函数,正例中入参通过状态变量传递。

优化后,aboutToReuse中只是通过变量传参,无需重复执行计算函数,耗时缩短为2ms。

noFuncParam

所以,Trace数据证明,避免使用函数/方法作为复用组件创建时的入参,可以减少重复执行入参中的函数所带来的性能消耗。

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

GitCode - 全球开发者的开源社区,开源代码托管平台希望这一份鸿蒙学习文档能够给大家带来帮助~


鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频学习教程+学习PDF文档

HarmonyOS Next 最新全套视频教程

  纯血版鸿蒙全套学习文档(面试、文档、全套视频等)       

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线


http://www.kler.cn/a/291666.html

相关文章:

  • 小程序快速实现大模型聊天机器人
  • 京准电钟:电厂自控NTP时间同步服务器技术方案
  • C++ OpenGL学习笔记(2、绘制橙色三角形绘制、绿色随时间变化的三角形绘制)
  • 消息队列 Kafka 架构组件及其特性
  • 投标心态:如何在“标海战术”中保持清醒的头脑?
  • APM32F411使用IIS外设驱动es8388实现自录自播
  • 基于vue框架的车辆交易管理系统n5xwr(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • day17JS-Cookle、webStorage和Promise
  • Day22_K8S
  • 使用GPU加速及配置
  • UNION和UNION ALL的区别
  • 假如你是HR,你怎么招「游戏策划」?
  • 创建一个Oracle版本的JDK的Docker镜像
  • taro ui 小程序at-calendar日历组件自定义样式+选择范围日历崩溃处理
  • PyTorch常用库函数:torch.acos()的详解实战使用
  • 世界时钟怎么设置?一键设置多个世界时钟 多个地区时间
  • 向量和矩阵学习笔记
  • vue3 VueUse useElementVisibility 来监听某一个元素或者div是否在当前视口viewport中可见。
  • 坐牢第三十五天(c++)
  • 智能手机、汽车新应用,星纪魅族幸运星号”卫星即将发射
  • 如何用 Typed.js 制作炫酷的打字效果?
  • 【避坑指南】避免几个坑,OpenCV的轮廓分析速度也可以很快!
  • 【C-实践】一对一的远程通信(tcp+epoll)
  • 浅谈维度建模、数据分析模型,何为数据仓库,与数据库的区别
  • Shell脚本字符串处理(Linux篇)
  • 机器人笛卡尔空间轨迹规划原理与MATLAB实现