Harmony os——ArkTS 高性能编程实践 – 速查笔记

ArkTS 高性能编程实践 -- 速查笔记

场景:性能敏感代码 (比如频繁调用、深层循环、动画/渲染逻辑等)

目标:在写业务代码的同时,顺手带上高性能写法习惯。


一、声明与表达式

1.1 使用 const 声明不变的变量

  • 原则 :只读、不再修改的变量用 const,方便引擎做优化。
ts 复制代码
// ✅ 推荐
const index = 10000;

// ❌ 不推荐:逻辑上不会变却用 let
let index = 10000;

1.2 number 避免整型 / 浮点型混用

ArkTS 运行时会区分 "整型 number" 和 "浮点 number",混着用会让优化失效。

复制代码
// ❌ 不推荐:int ➜ double
let intNum = 1;
intNum = 1.1;   // 声明时是整数,后面变成小数

// ❌ 不推荐:double ➜ int
let doubleNum = 1.1;
doubleNum = 1;  // 声明时是小数,后面赋值为整数

// ✅ 推荐:类型风格保持一致
let scoreInt: number = 0;     // 一直用整数
let scoreDouble: number = 0.0; // 一直用小数

1.3 数值计算避免溢出

原因:溢出后会走"慢路径",性能变差。

  • + - * ** 运算:尽量保证在 INT32_MIN ~ INT32_MAX 范围内
    • INT32_MAX = 2147483647
    • INT32_MIN = -2147483648
  • &>>> 等位运算:同样避免超过 INT32_MAX

简单理解:

  • 做位运算 / 累加计数时不要让值无限增长,及时裁剪(比如 & 0xffff 或重置)。

1.4 循环中提取常量,减少属性访问

问题代码:每次循环都访问 class 静态属性 + 计算

复制代码
class Time {
  static start: number = 0;
  static info: number[] = [1,2,3,4,5,6,7,8,9,10,11,12];
}

function getNum(num: number): number {
  let total: number = 348;
  for (let index: number = 0x8000; index > 0x8; index >>= 1) {
    total += ((Time.info[num - Time.start] & index) !== 0) ? 1 : 0;
  }
  return total;
}

优化:把循环不变的值缓存到局部常量

复制代码
function getNum(num: number): number {
  let total: number = 348;
  const info = Time.info[num - Time.start]; // ✅ 循环外提取

  for (let index: number = 0x8000; index > 0x8; index >>= 1) {
    if ((info & index) != 0) {
      total++;
    }
  }
  return total;
}

"循环里用到但不会改变的东西 → 提前拿出来当局部 const"。


二、函数

2.1 尽量用参数传递,而不是闭包捕获外部变量

问题:闭包 = 引擎额外维护环境,性能有成本。

复制代码
// ❌ 闭包捕获外部变量
let arr = [0, 1, 2];

function foo(): number {
  return arr[0] + arr[1];
}
foo();

优化:显式通过参数传入

复制代码
// ✅ 推荐
let arr = [0, 1, 2];

function foo(array: number[]): number {
  return array[0] + array[1];
}

foo(arr);

心法:性能敏感代码里,"从外面拿变量" 尽量走参数,而不是让函数偷偷闭包引用。


2.2 避免可选参数,使用"必选 + 默认值"

问题:可选参数意味着可能是 undefined,每次使用都要做判断。

复制代码
// ❌ 有可选参数,内部还要 if 判空
function add(left?: number, right?: number): number | undefined {
  if (left != undefined && right != undefined) {
    return left + right;
  }
  return undefined;
}

优化:改成必选参数 + 默认值

复制代码
// ✅ 推荐
function add(left: number = 0, right: number = 0): number {
  return left + right;
}

场景:

  • 一般工具函数 尽量设计成参数必传,需要"不传"时用默认值表达。

三、数组

3.1 纯数值运算 ➜ 用 TypedArray

普通数组:

复制代码
// ❌ 普通 number 数组
const arr1 = new Array<number>(1, 2, 3);
const arr2 = new Array<number>(4, 5, 6);
let res = new Array<number>(3);

for (let i = 0; i < 3; i++) {
  res[i] = arr1[i] + arr2[i];
}

TypedArray:

复制代码
// ✅ 推荐:TypedArray
const typedArray1 = Int8Array.from([1, 2, 3]);
const typedArray2 = Int8Array.from([4, 5, 6]);
let res = new Int8Array(3);

for (let i = 0; i < 3; i++) {
  res[i] = typedArray1[i] + typedArray2[i];
}

适用场景:矩阵运算、音频数据、图像 buffer、频繁数值计算等。


3.2 避免"稀疏数组"(sparse array)

稀疏数组 & 大数组(>1024)可能会被运行时转成 hash 表存储,访问会更慢。

复制代码
// ❌ 大小 100000 的数组:可能走 hash 存储
let count = 100000;
let result: number[] = new Array(count);

// ❌ 稀疏数组:直接给很远的索引赋值
let result2: number[] = new Array();
result2[9999] = 0;

建议:

  • 尽量使用 push 逐步填充

  • 或者用 new Array(count).fill(0) 初始化成"密集数组"

    // ✅ 密集数组
    let result: number[] = new Array(count).fill(0);


3.3 避免联合类型数组 & 数值类型混用

复制代码
// ❌ 数值数组里混合整型 + 浮点型
let arrNum: number[] = [1, 1.1, 2];

// ❌ 元素是 (number | string) 联合类型
let arrUnion: (number | string)[] = [1, 'hello'];

推荐: 不同类型的值分开存:

复制代码
// ✅ 分类型存储
let arrInt: number[] = [1, 2, 3];
let arrDouble: number[] = [0.1, 0.2, 0.3];
let arrString: string[] = ['hello', 'world'];

心法:

  • 数组 = 一种类型,而不是"什么都往里面丢一个"。

四、异常(Error)使用

4.1 性能敏感路径中避免频繁抛异常

抛异常时需要构造栈信息,是非常重 的操作。

特别是在 for 循环、热点函数中,不要用异常做控制流。

问题代码:

复制代码
function div(a: number, b: number): number {
  if (a <= 0 || b <= 0) {
    throw new Error('Invalid numbers.');
  }
  return a / b;
}

function sum(num: number): number {
  let sum = 0;
  try {
    for (let t = 1; t < 100; t++) {
      sum += div(t, num);
    }
  } catch (e) {
    console.info(e.message);
  }
  return sum;
}

优化思路:

  • 返回特殊值 (NaN / -1 / null) 表示异常,而不是直接 throw

  • 循环内部做快速判断,避免频繁进入 catch

    function div(a: number, b: number): number {
    if (a <= 0 || b <= 0) {
    return NaN; // ✅ 用返回值表达错误
    }
    return a / b;
    }

    function sum(num: number): number {
    let sum = 0;
    for (let t = 1; t < 100; t++) {
    if (num <= 0) { // ✅ 提前拦截非法情况
    console.info('Invalid numbers.');
    break; // 可视情况 break / continue
    }
    sum += div(t, num);
    }
    return sum;
    }

经验法则:

  • 异常只用在"真正异常的情况",而不是普通业务条件判断。
  • 热路径里宁可多几次 if,也少一次 throw

五、实战时可以直接套用的"小 Checklist"

写 ArkTS 性能敏感代码时,可以过一遍这几个问题:

  1. 常量是不是都用 const
    • 会不会修改?不会就用 const
  2. number 有没有从 int 变 double 或反过来?
    • 是否统一风格?
    • 是否可能越界 int32?
  3. 循环里有没有可以提到外面的不变量?
    • 静态属性、数组索引结果、复杂表达式等。
  4. 函数是不是在闭包里偷偷引用外部变量?
    • 能否通过参数传进去?
  5. 函数参数用的是可选参数吗?
    • 能否改成"必选+默认值"?
  6. 数组是不是稀疏的 / 超大 / 元素类型杂?
    • 能否用 TypedArray 或分类型数组?
  7. for/热点代码里有频繁 throw / try...catch 吗?
    • 能否用返回码 / NaN / null 代表错误?
相关推荐
iiiiii111 小时前
【论文阅读笔记】IDAQ:离线元强化学习中的分布内在线适应
论文阅读·人工智能·笔记·学习·算法·机器学习·强化学习
点亮一颗LED(从入门到放弃)1 小时前
C语言学习笔记(1)——输入输出,数据类型
c语言·笔记·学习
土拨鼠烧电路1 小时前
RPA悖论迷思:从解放的利器到运维的枷锁?
大数据·运维·笔记·rpa
IMPYLH1 小时前
Lua 的 select 函数
java·开发语言·笔记·后端·junit·游戏引擎·lua
云半S一1 小时前
春招准备之测试基础理论篇
经验分享·笔记·功能测试·测试覆盖率
摇滚侠1 小时前
2025最新 SpringCloud 教程,Nacos-注册中心-服务发现功能,笔记07
笔记·spring cloud·服务发现
平平不平凡2 小时前
Grid组件核心参数解析:控制器与布局选项详解
harmonyos
灰灰勇闯IT2 小时前
Flutter×VS Code:跨端开发的高效协作指南(2025最新配置)
笔记·flutter·harmonyos
d111111111d2 小时前
STM32-外设学习-读写备份寄存器(代码)--学习笔记
笔记·stm32·单片机·嵌入式硬件·学习