
【最新鸿蒙应用开发】——优化之编程规范(总结arkts和typescript编程规范)
开发过程中逐步总结出来的一些关于typescript和arkts代码提高性能的写法和建议,在业务功能实现过程中,我们要同步思考并理解高性能写法的原理,运用到代码逻辑实现中。
开发过程中逐步总结出来的一些关于typescript和arkts代码提高性能的写法和建议,在业务功能实现过程中,我们要同步思考并理解高性能写法的原理,运用到代码逻辑实现中。
优化--高性能编程规范
在平时进行代码编写的时候就需要有意识地遵循一些标准的高性能书写规范(我总结了大概八个方面的规范),具体如下:
一、声明
1、变量声明
-
使用const声明常量
对于初期明确不会改变的变量,尽量使用const进行初始化,这里的常量包含基础类型和引用类型。通过const保证地址不会发生变化,能够极大减少由于编码时误操作导致的赋值等行为,造成对原有逻辑的改变,声明为const能够在编辑时及时发现错误。其中当const声明的是引用类型时,引用类型内部的属性变化是允许的,对于这种不存在地址变化的情况下,也建议使用const声明。
-
指定number的类型
对于number类型,编译器在优化时会区分int和double类型。开发者在初始化number类型的变量时,如果预期是整数类型就初始化为0,小数类型就初始化为0.0,避免将一个number类型初始化为undefined或者null。
-
减少使用ESObject
ESObject主要用于在ArkTS和TS/JS跨语言调用的场景中作为类型标注,在非跨语言场景中使用ESObject标注类型,会引入不必要的跨语言调用,造成额外的性能开销,建议在非跨语言调用的场景下,避免使用ESObject,引入明确的类型进行注释。
2、常量提取,减少属性访问次数
应用开发中,在循环中会大量进行一些常量的访问操作,该常量在循环中不会改变,可以提取到循环外部,减少属性访问的次数。
二、属性访问
1、减少变量的属性查找
在要求性能的场景下,建议通过使用将全局变量存储为局部变量的方式来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快。重复的访问同一个变量,将造成不必要的消耗,尤其当类似的访问出现在循环过程中,其对于性能的影响更大。
2、给类属性添加访问修饰符
在ArkTS中,对于类结构的属性提供了private、protected和public可访问修饰符。默认情况下一个属性的可访问修饰符为public。选取适当的可访问修饰符可以提升代码的安全性、可读性。
3、避免频繁使用delete
delete对象的某一个属性会改变其布局,影响运行时优化效果,导致执行性能下降。不建议直接使用delete删除对象的任何属性,如果有需要,建议使用map和set或者引擎实现的高性能容器类。
// 例1:将Object中不再使用的属性设置为null
class O1 {
x: string | null = "";
y: string | null = "";
}
let obj: O1 = {x: "", y: ""};
obj.x = "xxx";
obj.y = "yyy";
obj.x = null;
// 例2:使用高性能容器类操作属性
import HashMap from '@ohos.util.HashMap';
let myMap= new HashMap();
myMap.set("x", "xxx");
myMap.set("y", "yyy");
myMap.remove("x");
三、数值计算
1、数值计算使用TypedArray
如果是纯数值计算的场合,推荐使用TypedArray数据结构。TypedArray类型化数组是一种类似数组的对象,其提供了一种用于在内存缓冲中访问原始二进制数据的机制。在一些图像数据处理、加解密的数据计算过程中使用TypedArray可以提高数据处理的效率,因为TypedArray是基于ArrayBuffer实现,在性能方面也能够进行较大提升。
2、数值计算避免溢出
四、数据结构
1、使用合适的数据结构
有些时候会采用Record的方式作为临时容器来处理属性存取的逻辑,例如如下案例中,对于info执行的操作是set存储以及读取的操作,这里更好的方式是采用标准内置Map以及基础类库提供的高性能容器类如HashMap。HashMap是ArkTS提供的高性能容器类,底层使用红黑树实现,提供了高性能的数据读写操作,可以用来实现快速读写键值。
2、避免使用稀疏数组
分配数组时,需要避免使用如下的方式进行处理。当虚拟机在分配大小超过1024大小的数组时,会变成用哈希表来存储元素,相对数组用偏移来访问元素速度较慢,在开发时,尽量避免数组变成稀疏数组。
五、对象初始化
1、使用字面量进行对象创建
在要求性能的场合,可以使用字面量进行对象创建,这样在运行时可以获得指令级别的优化。
2、对象构造初始化
对象构造的时候,要提供默认值初始化,不要访问未初始化的属性。
3、number正确初始化
针对number类型,编译器在优化时会区分整型和浮点类型。开发者在初始化时如果预期是整型就初始化成0,如果预期是浮点型就初始化为0.0,不要把一个number类型初始化成undefined或者null。
4、避免动态添加属性
对象在创建的时候,如果开发者明确后续还需要添加属性,可以提前置为undefined。动态添加属性会导致对象布局变化,影响编译器和运行时优化效果。
5、调用构造函数的入参要与标注类型匹配
由于TS语言类型系统是一种标注类型,不是编译期强制约束,如果入参的实际类型与标注类型不匹配,会影响引擎内部的优化效果。例如:入参类型是number类型,需要显式写出来。不然会造成标注的入参是number,实际传入的是undefined。
6、不变的变量声明为const
不变的变量推荐使用const进行初始化,例如对象。
六、接口及继承
1、避免使用type类型标注
如果传入的参数类型是type类型,实际入参可能是一个object literal,也可能是一个class,编译器及虚拟机因为类型不固定,无法做编译期假设进而进行相应的优化。
七、函数调用
1、声明参数要和实际的参数一致
声明的参数要和实际的传入参数个数及类型一致,如果不传入参数,则会作为undefined处理,可能造成与实际入参类型不匹配的情况,从而导致运行时走入慢速路径,影响性能。
2、函数内部变量尽量使用参数传递
能传递参数的尽量传递参数,不要使用闭包。闭包作为参数会多一次闭包创建和访问。
八、函数与类声明
1、避免动态声明function与class
以如下用例为例,动态声明了class Add和class Sub,每次调用foo
都会重新创建class Add和class Sub,对内存和性能都会有影响。
【反例】
function foo(f: boolean) {
if (f) {
return class Add{};
} else {
return class Sub{};
}
}
【正例】
class Add{};
class Sub{};
function foo(f: boolean) {
if (f) {
return Add;
} else {
return Sub;
}
}
2、函数内部变量尽量使用参数传递
能传递参数的尽量传递参数,不要使用闭包,闭包作为参数会多一次闭包的创建和访问。在普通函数中,修改外部作用域的变量时,建议通过函数的参数传递,因为在直接声明时引用外部作用域的变量,如果没有及时清理,可能有内存泄漏的风险。ArkTS中函数参数是引用类型时,作用于引用类型的修改会进行引用传递,函数内对形参的修改也会作用在实参上。
更多推荐
所有评论(0)