代码性能优化,很多时候藏在细节里。提升运行效率的几个关键:变量声明、属性访问、数值计算与数据结构、模块导出优化,以及通过路径展开提升冷启动性能。

一、变量声明

1. 尽量使用 const 声明常量

对于初期明确不会改变的变量,尽量使用 const 声明常量。

常量范围:包括基础类型和引用类型。

好处:

  • 通过 const 声明,可以确保地址不会变化

  • 减少因误操作导致的赋值错误,从而避免逻辑改变

  • 在编辑时及时发现错误

2. number 类型区分 int 和 double

对于 number 类型,编译器在优化时会区分 int 和 double 类型。

写法建议:

  • 初始化 number 类型的变量时指定 number 的类型

  • 如果预期是整数类型就初始化为 0

  • 如果是小数类型就初始化为 0.0

  • 避免将一个 number 类型初始化为 undefined 或者 null

3. 减少使用 ESObject

ESObject 主要用于 ArkTS 和 TS/JS 跨语言调用的类型标注。

在非跨语言场景中使用 ESObject 会引入不必要的跨语言调用,造成额外性能开销。

建议:

在非跨语言调用的场景下,减少使用 ESObject,引入明确的类型进行注释。

二、属性访问

1. 减少变量的属性查找

在要求性能的场景下,建议通过将全局变量存储为局部变量的方式来减少变量的属性查找。

原理:访问局部变量比访问全局变量更快。

说明:重复访问同一变量会造成不必要的消耗,尤其是在循环中,对性能的影响更大。

2. 给类属性添加访问修饰符

在 ArkTS 中,类结构的属性支持 private、protected 和 public 可访问修饰符。

默认情况:属性的可访问修饰符为 public。

建议:

给类属性添加访问修饰符,选取适当的可访问修饰符可以提升代码的安全性、可读性。

三、数值计算与数据结构

1. 纯数值计算推荐 TypedArray

如果是纯数值计算的场合,推荐数值计算使用 TypedArray 数据结构。

说明:

TypedArray 类型化数组是一种类似数组的对象,提供在内存缓冲区中访问原始二进制数据的机制。

适用场景:

  • 图像数据处理

  • 加解密计算

原因:TypedArray 基于 ArrayBuffer 实现,在性能方面有显著提升。

2. 选取合适的数据结构

通过选取合适的数据结构提高运行效率。

示例:

数据结构适用场景
Record作为临时容器处理属性存取逻辑
HashMap实现快速读写键值

HashMap 说明:

HashMap 是 ArkTS 提供的高性能容器类,底层使用红黑树实现,支持高效的数据读写操作。

四、模块导出与延迟加载

1. 减少同文件大量 export * 导出方式

原理:

由于依赖模块解析采用深度优先遍历,会从入口文件的第一个导入语句开始逐层查找,直到最后一个没有导入语句的模块。连接好该模块的导出变量后,再回到上一级模块重复此步骤。

建议:

减少同文件大量 export * 导出方式,降低依赖模块解析、文件执行阶段耗时增长。

2. 延迟加载(lazy import)

当工具类中存在较多暴露函数或变量时,推荐:

  • 按需引用使用到的变量

  • 使用延迟加载(lazy import)

好处:可以减少该阶段中 .ets 文件执行耗时,即减少文件中所有 export 变量的初始化过程。

五、通过路径展开提升运行效率

传统 HAR 包导入时,即使只需要 HAR 包中单个变量,也会触发整个依赖链所有模块的加载和执行,造成性能浪费。

解决方案:expandImportPath

ArkTS 编译器提供 expandImportPath 配置项。

原理:通过修改配置项,编译器会将间接包名导入转换为精准的文件路径导入,跳过中间模块。

好处:该优化可消除冗余的模块解析和初始化,减少冷启动阶段不必要的资源消耗。

注意

由于 import 路径展开会跳过中间模块的执行,若业务依赖模块的执行顺序,修改后可能会导致业务异常。

示例:未使用路径展开

问题代码:

// entry/src/main/ets/pages/Index.ets
// Before optimization: Namespace Import
import { hilog } from '@kit.PerformanceAnalysisKit';
import * as library from 'library';

hilog.info(0x0000, 'testTag', 'library.typeNum is %{public}d', library.typeNum);

说明:

即使只需要使用 typeNum 变量,但当使用 import * 全量导入 HAR 包时,所有关联模块(如 Animals.ets 等)仍会被加载执行,这会带来不必要的性能开销。

library 模块结构:

// library/src/main/ets/Animals.ets
import { hilog } from '@kit.PerformanceAnalysisKit';
export * from './Birds';
export * from './Fish';
export * from './Mammals';
export * from './TypeNum';
hilog.info(0x0000, 'testTag', 'library Animals.ets execute.');

即使用 import * as library,也会触发 Animals.ets、Birds.ets、Fish.ets、Mammals.ets、TypeNum.ets 全部执行。

代码示例:使用路径展开

优化方式:

  1. 配置 expandImportPath 启用路径展开功能

  2. 将导入方式改为:

import { typeNum } from 'library';

效果:

使源码中的 import 语句在编译时指向被引用符号的实际定义文件。从 Trace 上看,此时只执行 TypeNum.ets,同时通过修改前后的 Trace 对比也可以看出冷启动性能得到提升。

关键点:

  1. const 是"零成本"优化:不改变的变量全部用 const,既防误改又便于编译器优化,没有理由不用。

  2. number 初始化:整数用 0,小数用 0.0,别用 undefined 或 null。编译器会区分 int 和 double,初始化时给对类型能避免运行时类型转换。

  3. ESObject 是"跨语言专用" :只在 ArkTS 调 TS/JS 时用,非跨语言场景用了会引入额外跨语言调用开销,能用明确类型就别用 ESObject。

  4. 局部变量比全局变量快:把全局变量存为局部变量,减少属性查找。循环中尤其重要,重复查找的累积开销很大。

  5. TypedArray 是数值计算的利器:图像处理、加解密计算用 TypedArray,基于 ArrayBuffer,性能显著优于普通数组。

  6. HashMap 底层是红黑树:需要快速读写键值时用 HashMap,比普通对象更高效。

  7. export * 有解析成本:依赖解析是深度优先遍历,export * 越多,解析和执行越慢。按需导出、按需引用更高效。

  8. lazy import 减少初始化:工具类函数多时,用 lazy import 按需加载,减少 .ets 文件中所有 export 变量的初始化过程。

  9. expandImportPath 是冷启动优化:

    • 问题:import * 会触发整个依赖链加载执行

    • 解决:配置 expandImportPath,把间接包名导入转为精准文件路径导入,跳过中间模块

    • 效果:只执行实际用到的文件,冷启动性能提升

  10. 路径展开风险:跳过中间模块执行可能影响依赖模块执行顺序的业务逻辑。有副作用的模块(如初始化配置、注册事件)要注意,改之前先确认依赖关系。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐