【最新鸿蒙开发之性能优化——动态加载和延迟加载】

大家好,我是学徒小z,在经历了一段时间项目开发中,我也渐渐意识到了性能的重要性,今天就分享一篇优化应用运行性能的文章,话不多说,开干!

引言

延时触发操作与延迟加载的简介

  • 动态加载(动态import)是一种模块加载机制,允许应用程序在运行时按照实际需求去加载相关模块。在某些条件满足时(比如用户交互时,或分支切换时)再加载特定模块,可以减少初始化import的加载时间和资源消耗,这将有助于提高应用程序的内存性能和响应速度。
  • 以通过延迟加载 Lazy-Import的方法延缓对这些冗余文件的加载,使待加载文件在冷启动阶段不被加载,而在后续导出变量被真正使用时再同步加载执行文件,节省资源以提高应用冷启动性能。
  • Lazy-Import与动态加载都可以实现主动延后特定文件的执行时间,帮助设备均摊性能消耗,缓解特定时段性能压力的能力。

动态加载(Dynamic Import)

1. 动态加载适用场景

动态加载是指在代码运行时,根据需要按需导入模块的技术。它适用于以下场景:

  • 性能优化场景

    • 当模块明显降低代码加载速度

    • 当模块占用大量系统内存

    • 使用频率较低的功能模块

  • 按需加载场景

    • 模块在运行时才能确定是否需要

    • 模块需要异步获取

    • 模块路径需要动态构建

  • 条件执行场景

    • 模块中的代码只在特定条件下才需要执行
    • 模块的功能取决于用户的选择或系统状态

2. 动态加载的业务扩展

  • 条件延迟加载
    条件延迟加载允许根据特定条件决定是否加载模块:
// 根据用户权限加载不同功能
if (userHasAdminAccess) {
  const adminModule = await import('./admin/features');
  adminModule.initAdminFeatures();
}
  • 反射功能

反射(Reflection)是指程序在运行时能够访问、检测和修改它本身状态或行为的能力。

​ 在鸿蒙开发中,动态加载支持简单的反射功能:

// 动态调用类和方法
import('myModule').then((module) => {
  // 通过字符串动态访问类
  const className = 'UserManager';
  const ClassType = module[className];
  
  // 通过字符串动态访问方法
  const methodName = 'getUserInfo';
  const instance = new ClassType();
  instance[methodName]();
});

3. 动态加载的实现方案与关键点

  • 基本实现方式
    动态加载支持两种主要的实现方式:
  1. 常量表达式导入
// 直接使用字符串字面量
import('./modules/feature').then(module => {
  module.doSomething();
});
  1. 变量表达式导入
const modulePath = getModulePath(); // 动态确定模块路径
import(modulePath).then(module => {
  module.doSomething();
});

4. 配置要点

​ 当使用变量表达式进行动态导入时,需要在项目配置文件中添加特殊配置:

{
  "buildOption": {
    "arkOptions": {
      "runtimeOnly": {
        "packages": ["moduleA", "moduleB"],  // 需要动态导入的模块
        "sources": ["./src/feature.ets"]     // 需要动态导入的文件
      }
    }
  }
}

5. HAR模块间动态import依赖解耦

当应用包含多个HAR包,且HAR包之间依赖关系比较复杂。在IDE中配置依赖关系时,可能会形成循环依赖。这时,如果HAR之间的依赖关系中仅有变量动态import,可以将HAR包之间直接依赖关系转移到HAP/HSP中配置,HAR包之间无需配置依赖关系,从而达到HAR包间依赖解耦的目的。如下示意图:

image-20241117215421513

HAR之间依赖关系转移到HAP/HSP后

image-20241117215437871

  1. 仅适用于本地源码HAR包间的循环依赖。
  2. 被转移的HAR间只能通过变量动态import,不支持静态import或常量动态import。
  3. 转移依赖时,需要同时转移dependenciesruntimeOnly配置。
  4. HSP不支持转移依赖。
  5. 转移依赖的链路上只能有HAR,不能跨越HSP。

实例:

​ har1对har2的依赖dependencies和runtimeOnly配置转移到HAP中,har1不需要配置对har2的dependencies和runtimeOnly配置:

// HAP's oh-package.json5
"dependencies": {
  "har1": "file:../har1",
  "har2": "file:../har2"
}

// HAP's build-profile.json5
"buildOption": {
  "arkOptions": {
    "runtimeOnly": {
      "packages": [
        "har1",
        "har2"
      ]
    }
  }
}

// HAP's src/main/ets/pages/Index.ets
let harName = 'har1';
import(harName).then((ns:ESObject) => {
  console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5));
});

// har1's Index.ets
export { addHar1 } from './src/main/ets/utils/Calc'

// har1's src/main/ets/utils/Calc.ets
export function addHar1(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am har1, %d + %d = %d', a, b, c);

  let harName = 'har2';
  import(harName).then((ns:ESObject) => {
    console.info('DynamicImport addHar2 4 + 5 = ' + ns.addHar2(4, 5));
  });
  return c;
}

// har2's Index.ets
export { addHar2 } from './src/main/ets/utils/Calc'

// har2's src/main/ets/utils/Calc.ets
export function addHar2(a:number, b:number):number {
  let c = a + b;
  console.info('DynamicImport I am har2, %d + %d = %d', a, b, c);
  return c;
}

延迟加载(Lazy-Import)

1. 延迟加载的功能特性与使用方式

延迟加载特性可使待加载文件在冷启动阶段不被加载(但模块解析依然会在冷启动时触发),直至应用程序实际运行过程中需要用到这些组件时,才按需同步加载相关文件,从而缩短应用冷启动耗时

  • 需要注意的是,后续执行的加载是同步加载,有可能会阻塞任务执行(如点击任务,触发了延迟加载,那么运行时会去执行冷启动未加载的文件,从而增加耗时。
  • 使用lazy-import延迟加载
    // main.ets   
    import lazy { a } from "./mod1";    // "mod1" 未执行
    import { c } from "./mod2";         // "mod2" 执行
    
    // ...
    
    console.info("main executed");
    while (false) {
        let xx = a;
    }
    
    // mod1.ets
    export let a = "mod1 executed"
    console.info(a);
    
    // mod2.ets
    export let c = "mod2 executed"
    console.info(c);

//执行结果
//   mod2 executed
//   main executed

2. 延迟加载的场景行为与语法规格

lazy-import支持如下指令实现:

语法ModuleRequestImportNameLocalNameAPI12是否支持lazy加载
import lazy { x } from “mod”;“mod”“x”“x”支持
import lazy { x as v } from “mod”;“mod”“x”“v”支持
  • 延迟加载的错误示例

        export lazy var v;                  // 编译器提示报错:应用编译报错
        export lazy default function f(){}; // 编译器提示报错:应用编译报错
        export lazy default function(){};   // 编译器提示报错:应用编译报错
        export lazy default 42;             // 编译器提示报错:应用编译报错
        export lazy { x };                    // 编译器提示报错:应用编译报错
        export lazy { x as v };               // 编译器提示报错:应用编译报错
        export lazy { x } from "mod";         // 编译器提示报错:应用编译报错
        export lazy { x as v } from "mod";    // 编译器提示报错:应用编译报错
        export lazy * from "mod";           // 编译器提示报错:应用编译报错
        
        import lazy v from "mod";           // 编译器提示报错:应用编译报错
        import lazy * as ns from "mod";     // 编译器提示报错:应用编译报错
    

3. 使用场景

下述例子中A文件被引用,在应用启动到点击按钮的这段时间里,A文件并没有被实际执行,在冷启动阶段加载A文件的行为属于冗余。

// A为任意可以被引入的ets文件
import { A } from "./A"

@Entry
@Component
struct Index {
  build() {
    RelativeContainer() {
      Button('点击执行A')
        .onClick(() => {
          console.log('执行A' + A)
        })
    }
    // ...
  }
}

通过抓取Trace图查看调用栈可发现,应用在冷启动时加载了A文件。

技术对比与应用选择:

  • Lazy-Import与Dynamic Import的区别
动态加载Lazy-Import
语法示例let A= await import(“./A”);import lazy { A } from “./A”
性能开销创建异步任务开销。执行到动态加载时,触发依赖模块的模块解析+源码执行。Lazy-Import的模块解析耗时在冷启动依旧会触发遍历。导入的变量A被使用到时,触发模块的源码执行。
使用位置代码块/运行逻辑中使用需要写在源码开头
是否可以运行时拼接待加载模块名
加载时序异步同步

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云计算研究实训室建设方案

一、引言 随着云计算技术的迅速发展和广泛应用,职业院校面临着培养云计算领域专业人才的迫切需求。本方案旨在构建一个先进的云计算研究实训室,为学生提供一个集理论学习、实践操作、技术研发与创新于一体的综合性学习平台,以促进云计算技术…

信号保存和信号处理

目录 信号保存中重要的概念 内核中信号的保存 对sigset_t操作的函数 对block,pendding,handler三张表的操作 sigpromask ​编辑 sigpending 是否有sighandler函数呢? 案例 信号处理 操作系统是如何运行的? 硬件中断 …

用vscode编写verilog时,如何有信号定义提示、信号定义跳转(go to definition)、模块跳转(跨文件跳转)这些功能

(一)方法一:安装插件SystemVerilog - Language Support 安装一个vscode插件即可,插件叫SystemVerilog - Language Support。虽然说另一个插件“Verilog-HDL/SystemVerilog/Bluespec SystemVerilog”也有信号提示及定义跳转功能&am…

初识算法 · 模拟(1)

目录 前言: 替换所有的问号 题目解析 算法原理 算法编写 提莫攻击 题目解析 算法原理 算法编写 外观数列 题目解析 算法原理 算法编写 前言: ​本文的主题是模拟,通过三道题目讲解,一道是提莫攻击,一道是…

〔 MySQL 〕数据类型

目录 1.数据类型分类 2 数值类型 2.1 tinyint类型 2.2 bit类型 2.3 小数类型 2.3.1 float 2.3.2 decimal 3 字符串类型 3.1 char 3.2 varchar 3.3 char和varchar比较 4 日期和时间类型 5 enum和set mysql表中建立属性列: 列名称,类型在后 n…

数据结构王道P234第二题

#include<iostream> using namespace std; int visit[MAxsize]; int color[MaxSize];//1表示红&#xff0c;2表示白&#xff1b; bool dfs(Graph G, int i){visit[i]1;ArcNode *p;bool flag1;for(pG.vertices[i].firsrarc; p ; pp->next){int jp->adjvex;if(!visi…

算法——两两交换链表中的节点(leetcode24)

这是一道对于链表节点进行操作的题目非常考验对于链表操作的基本功&#xff1b; 解法: 本题的解法结合下图来进一步解释 创建一个虚拟节点指向头结点以便使代码逻辑看起来更为简便且操作节点容易,定义cur是为了方便找到cur之后的两个节点进行交换操作定义pre和aft是为了保存执…

【AI图像生成网站Golang】项目架构

AI图像生成网站 目录 一、项目介绍 二、雪花算法 三、JWT认证与令牌桶算法 四、项目架构 五、图床上传与图像生成API搭建 六、项目测试与调试(等待更新) 四、项目架构 本项目的后端基于Golang和Gin框架开发&#xff0c;主要包括的模块有&#xff1a; backend/ ├── …

翼鸥教育:从OceanBase V3.1.4 到 V4.2.1,8套核心集群升级实践

引言&#xff1a;自2021年起&#xff0c;翼鸥教育便开始应用OceanBase社区版&#xff0c;两年间&#xff0c;先后部署了总计12套生产集群&#xff0c;其中核心集群占比超过四分之三&#xff0c;所承载的数据量已突破30TB。自2022年10月&#xff0c;OceanBase 社区发布了4.2.x 版…

ESP32-S3模组上跑通esp32-camera(19)

接前一篇文章&#xff1a;ESP32-S3模组上跑通esp32-camera&#xff08;18&#xff09; 本文内容参考&#xff1a; esp32-camera入门&#xff08;基于ESP-IDF&#xff09;_esp32 camera-CSDN博客 OV5640手册解读-CSDN博客 ESP32_CAM CameraWebServer例程源码解析笔记&#xf…

vmWare虚拟环境centos7安装Hadoop 伪分布式实践

背景&#xff1a;近期在研发大数据中台&#xff0c;需要研究Hadoop hive 的各种特性&#xff0c;需要搭建一个Hadoop的虚拟环境&#xff0c;本来想着使用dock &#xff0c;但突然发现docker 公共仓库的镜像 被XX 了&#xff0c;无奈重新使用vm 搭建虚拟机。 大概经历了6个小时完…

ARM(安谋) China处理器

0 Preface/Foreword 0.1 参考博客 Cortex-M23/M33与STAR-MC1星辰处理器 ARM China&#xff0c;2018年4月established&#xff0c;独立运行。 1 处理器类型 1.1 周易AIPU 1.2 STAR-MC1&#xff08;星辰处理器&#xff09; STAT-MC1&#xff0c;主要为满足AIOT应用性能、功…

c++--------《set 和 map》

c--------《set 和 map》 1 set系列的使⽤1.1 set类的介绍1.2 set的构造和迭代器1.3 set重要接口 2 实现样例2.1: insert和迭代器遍历使⽤样例&#xff1a;2.2: find和erase使⽤样例&#xff1a; 练习3.map系列的使用3.1 map类的介绍3.1.1 pair类型介绍 3.2 map的数据修改3.3mu…

MySQL面试之底层架构与库表设计

华子目录 mysql的底层架构客户端连接服务端连接的本质&#xff0c;连接用完会立马丢弃吗解析器和优化器的作用sql执行前会发生什么客户端的连接池和服务端的连接池数据库的三范式 mysql的底层架构 客户端连接服务端 连接的本质&#xff0c;连接用完会立马丢弃吗 解析器和优化器…

vscode vite+vue3项目启动调试

1、经常我们在普通的项目中&#xff0c;如果算法并不复杂&#xff0c;那么基本上console.log就可以搞定&#xff0c;当然也可以直接alert&#xff0c;打包的时候如果不去掉&#xff0c;还会在发版中上接弹出&#xff0c;给你个惊喜。 2、碰到了有些算法过程比较复杂的情况下&a…

详解八大排序(一)------(插入排序,选择排序,冒泡排序,希尔排序)

文章目录 前言1.插入排序&#xff08;InsertSort&#xff09;1.1 核心思路1.2 实现代码 2.选择排序&#xff08;SelectSort&#xff09;2.1 核心思路2.2 实现代码 3.冒泡排序&#xff08;BubbleSort&#xff09;3.1 核心思路3.2 实现代码 4.希尔排序&#xff08;ShellSort&…

IPv6 NDP 记录

NDP&#xff08;Neighbor Discovery Protocol&#xff0c;邻居发现协议&#xff09; 是 IPv6 的一个关键协议&#xff0c;它组合了 IPv4 中的 ARP、ICMP 路由器发现和 ICMP 重定向等协议&#xff0c;并对它们作出了改进。该协议使用 ICMPv6 协议实现&#xff0c;作为 IPv6 的基…

【包教包会】CocosCreator3.x框架——带翻页特效的场景切换

一、效果演示 二、如何获取 1、https://gitee.com/szrpf/TurnPage 2、解压&#xff0c;导入cocos creator&#xff08;版本3.8.2&#xff09;&#xff0c;可以直接运行Demo演示 三、算法思路 1、单场景 页面预制体 通过loadScene来切换页面&#xff0c;无法实现页面特效。…

拉取docker镜像应急方法

发现许多docker hub镜像网址速度也慢得发指啦&#xff0c;如果想速度快点&#xff0c;可以考虑买个按量计费的公有云服务器&#xff0c;用他们的内网镜像&#xff0c;然后再导出&#xff0c;然后传到本地。 开通服务器 可以考虑个开通最低配的&#xff0c;这里我用的是腾讯的…

Cyberchef配合Wireshark提取并解析HTTP/TLS流量数据包中的文件

本文将介绍一种手动的轻量级的方式&#xff0c;还原HTTP/TLS协议中传输的文件&#xff0c;为流量数据包中的文件分析提供帮助。 如果捕获的数据包中存在非文本类文件&#xff0c;例如png,jpg等图片文件&#xff0c;或者word&#xff0c;Excel等office文件异或是其他类型的二进…