鸿蒙(HarmonyOS)性能优化实战-运行时动态加载页面性能

871 篇文章 13 订阅
695 篇文章 15 订阅

简介

应用在加载页面时,如果引入大量暂不需要加载的模块,会因过多模块导致页面加载缓慢。比如当页面在使用Navigation组件时,主页默认先加载所有页面,此时若包含大量子页面,仅加载主页这一项就需要很长时间,但这些复杂的子页面与主页渲染无关。
本文推荐使用动态加载解决上述问题,不在应用程序加载时就将所有模块都加载进来,而是按需加载模块,增加应用灵活性,提升应用性能。

场景示例

下面示例应用通过Navigation组件常规加载与动态加载的对比,介绍如何在跳转时触发加载方法,实现按需加载子模块。

常规加载

开发者使用Navigation组件时,通常会在主页引入各子页面组件,在按钮中添加方法实现跳转。下述代码展示常规加载示例,通过import引入子组件。

  1. 加载模块引入子页面,Navigation组件使用这些子模块实现跳转子页面功能,但用户进入主页时并不会马上使用到这些模块,存在冗余加载影响性能的可能。
    import { pageOne, pageOneData } from './pageOne';
    import { pageTwo, pagesTwoData } from './pageTwo';
    ...
    import router from '@ohos.router';
  1. 主页通过Navigation组件实现点击Button跳转到不同的子页面。
    @Provide('pathInfos') pageInfos: NavPathStack = new NavPathStack();
    
    @Builder
    PageMap(name: string) {
      if (name === 'pageOne') {
        pageOne(new pagesOneData(name, this.pageInfos));
      } else if (name === 'pageTwo') {
        pageTwo(new pagesTwoData(name, this.pageInfos));
      }
      ...
    }
    
    build() {
      Navigation(this.pageInfos) {
        Button('返回', { stateEffect: true, type: ButtonType.Capsule })
          .onClick(() => {
             router.back();
          })
        Column() {
          Button('pageOne', { stateEffect: true, type: ButtonType.Capsule })
            .onClick(() => {
               this.pageInfos.pushPath({ name: 'pageOne' }); // 将name指定的NavDestination页面信息入栈
            })
          Button('pageTwo', { stateEffect: true, type: ButtonType.Capsule })
            .onClick(() => {
               this.pageInfos.pushPath({ name: 'pageTwo' });
            })
          ...
        }
      }.title('主页').navDestination(this.PageMap)
    }

动态加载

当子组件较多、较复杂时,由于Navigation组件一次性加载所有模块,使用常规加载会导致主页加载缓慢。为了减少主页渲染时间,可以使用动态加载,在实际页面跳转时再按需动态引入子组件,优化用户的首次加载速度体验。以下是动态加载实现步骤:

  1. 将需要被动态加载的组件pageOne组件用PageOneLoader函数封装,当PageOneLoader被调用时,会渲染pageOne页面。
    import { pageOne } from './pageOne';
    
    @Builder
    export function PageOneLoader() {
      pageOne();
    }
  1. 由于在Navigation的PageMap中navDestination无法直接动态加载组件(import是函数,组件中无法引用函数),此处采用声明 @BuilderParam PageOneLoader 函数,在点击时初始化此函数,此时navDestination中可以调用 this.PageOneLoader() 从而加载组件pageOne。
    在主页DynamicHome实现动态加载pageOne的步骤如下:
    a) 在主页DynamicHome中定义组件加载函数 @BuilderParam PageOneLoader: () => void ,用来承接await import异步导入pageOneLoader的结果。
    @BuilderParam PageOneLoader: () => void;

b) 定义异步函数,点击时为PageOneLoader初始化。

    async loadPageOne(key: string){
      if (key === "pageOne") {
        let PageObj: ESObject = await import("../pages/PageOneLoader");
        this.PageOneLoader = PageObj.PageOneLoader;
      }
    }

c) 点击按钮触发点击函数,调用loadPageOne,此时真正的初始化 @BuilderParam PageOneLoader ,并使用Navigation加载组件。

    private onEntryClick(): void {
      try {
        this.loadPageOne('pageOne');
        this.pageInfos.clear();
        this.pageInfos.pushPathByName('pageOne', '');
        logger.info('DynamicImport Success');
      } catch (error) {
        logger.info('DynamicImport Fail');
      }
    }

d) 触发PageMap中已经被初始化的PageOneLoader函数,动态加载pageOne组件。

    @Builder
    PageMap(name: string) {
      if (name === 'pageOne') {
        this.PageOneLoader();
      }
    }

完整的DynamicHome主页代码如下:

import router from '@ohos.router';
import { logger } from '../../ets/utils/Logger';

@Entry
@Component
struct DynamicHome {
  @Provide('pathInfos') pageInfos: NavPathStack = new NavPathStack();
  @State active: boolean = false;
  @BuilderParam PageOneLoader: () => void;

  @Builder
  PageMap(name: string) {
    if (name === 'pageOne') {
      this.PageOneLoader();
    }
  }

  build() {
    Navigation(this.pageInfos) {
      Column() {
        Button('返回', { stateEffect: true, type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            router.back();
          })
        Button('PageOne-动态', { stateEffect: true, type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            this.onEntryClick();
          })
      }
    }.title('HOME').navDestination(this.PageMap)
  }

  async loadPageOne(key: String) {
    if (key === "pageOne") {
      let PageObj: ESObject = await import("../pages/PageOneLoader");
      this.PageOneLoader = PageObj.PageOneLoader;
    }
  }

  // 触发动态加载
  private onEntryClick(): void {
    try {
      this.loadPageOne('pageOne');
      this.pageInfos.clear();
      this.pageInfos.pushPathByName('pageOne', '');
      logger.info('DynamicImport Success');
    } catch (error) {
      logger.info('DynamicImport Fail');
    }
  }
}

当子页面逐渐增多时,Navigation组件使用常规加载会因默认加载所有子页面导致性能开销增大,主页内存占用增加,加载时间变长。此时改用动态加载不再提前加载子页面,可以有效地避免这些任务阻塞主线程,从而降低整体资源消耗,提高主页的加载速度。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值