• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ArkTS Performant Programming Practices
2
3## Overview
4
5
6This topic provides a set of performant programming practices that you can apply in performance-critical scenarios. They are techniques and recommendations drawn from real-world development. Following these practices in your service implementation can help develop performant applications. For details about ArkTS coding standards, see [ArkTS Coding Style Guide](./arkts-coding-style-guide.md).
7
8## Declaration and Expression
9
10### Using const to Declare Unchanged Variables
11
12You are advised to use **const** to declare variables that remain unchanged.
13
14``` TypeScript
15const index = 10000; // This variable does not change in the subsequent process. You are advised to declare it as a constant.
16```
17
18
19### Avoiding Mixed Use of Integers and Floating-Point Numbers in Variables of the number Type
20
21For variables of the **number** type, integer data and floating-point data are distinguished during optimization at runtime. As such, avoid changing the data type of the variables after they have been initialized.
22
23``` TypeScript
24let intNum = 1;
25intNum = 1.1; // This variable is declared as an integer data type. Avoid assigning a floating-point number to it.
26
27let doubleNum = 1.1;
28doubleNum = 1; // This variable is declared as a floating-point data type. Avoid assigning an integer to it.
29```
30
31
32### Avoiding Overflow in Arithmetic Operations
33
34When arithmetic operations run into overflow, the engine enters a slower logic branch for processing overflow, affecting subsequent performance. Below are some suggestions to mitigate the overflow risk.
35
36- For operations such as addition, subtraction, multiplication, and exponentiation, the value should not be greater than **INT32_MAX** or less than **INT32_MIN**.
37
38- For operations such as & (and) and >>> (unsigned right shift), the value should not be greater than **INT32_MAX**.
39
40
41### Extracting Constants in Loops to Reduce Attribute Access Times
42
43In a loop where there is frequent access to a constant that does not change, extract the constant outside of the loop to reduce the number of times the property is accessed.
44
45``` TypeScript
46class Time {
47  static start: number = 0;
48  static info: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
49}
50
51function getNum(num: number): number {
52  let total: number = 348;
53  for (let index: number = 0x8000; index > 0x8; index >>= 1) {
54    // The system searches for info and start of Time multiple times, and the values found each time are the same.
55    total += ((Time.info[num - Time.start] & index) !== 0) ? 1 : 0;
56  }
57  return total;
58}
59```
60
61This optimization extracts constants in **Time.info[num - Time.start]**, which greatly reduces the number of property access times and brings better performance. The optimized code is as follows:
62
63``` TypeScript
64class Time {
65  static start: number = 0;
66  static info: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
67}
68
69function getNum(num: number): number {
70  let total: number = 348;
71  const info = Time.info[num - Time.start];  // Extract constants from the loop.
72  for (let index: number = 0x8000; index > 0x8; index >>= 1) {
73    if ((info & index) != 0) {
74      total++;
75    }
76  }
77  return total;
78}
79```
80
81
82## Functions
83
84### Using Parameters to Pass External Variables
85
86Using closures may incur additional overhead for closure creation and access. In performance-sensitive scenarios, you are advised to use parameters to pass external variables instead of using closures.
87
88``` TypeScript
89let arr = [0, 1, 2];
90
91function foo(): number {
92  return arr[0] + arr[1];
93}
94
95foo();
96```
97
98You are advised to use parameter to pass external variables instead of using closures.
99``` TypeScript
100let arr = [0, 1, 2];
101
102function foo(array: number[]): number {
103  return array[0] + array[1];
104}
105
106foo(arr);
107```
108
109
110### Avoiding Optional Parameters
111
112An optional function parameter may be **undefined**. When such a parameter is used in the function, the system needs to check whether the parameter is null, which will cause extra overhead.
113
114``` TypeScript
115function add(left?: number, right?: number): number | undefined {
116  if (left != undefined && right != undefined) {
117    return left + right;
118  }
119  return undefined;
120}
121```
122
123Declare function parameters as mandatory parameters based on service requirements. You can use the default parameters.
124``` TypeScript
125function add(left: number = 0, right: number = 0): number {
126  return left + right;
127}
128```
129
130
131## Arrays
132
133### Prioritizing TypedArray for Value Arrays
134
135Where only arithmetic operations are involved, prefer **TypedArrays** over Arrays.
136
137Before optimization
138``` TypeScript
139const arr1 = new Array<number>([1, 2, 3]);
140const arr2 = new Array<number>([4, 5, 6]);
141let res = new Array<number>(3);
142for (let i = 0; i < 3; i++) {
143  res[i] = arr1[i] + arr2[i];
144}
145```
146
147After optimization
148``` TypeScript
149const typedArray1 = new Int8Array([1, 2, 3]);
150const typedArray2 = new Int8Array([4, 5, 6]);
151let res = new Int8Array(3);
152for (let i = 0; i < 3; i++) {
153  res[i] = typedArray1[i] + typedArray2[i];
154}
155```
156
157
158### Avoiding Sparse Arrays
159
160When allocating an array whose size exceeds 1024 or a sparse array, a hash table is used to store elements. This mode, compared with using an offset to access array elements, results in slower access speeds. Therefore, during development, avoid changing arrays into sparse arrays.
161
162``` TypeScript
163// Allocate an array of 100,000 bytes, for which a hash table is used to store elements.
164let count = 100000;
165let result: number[] = new Array(count);
166
167// The array will become a sparse array when the value is changed to 9999 after the array is created.
168let result: number[] = new Array();
169result[9999] = 0;
170```
171
172
173### Avoiding Arrays of Union Types
174
175When appropriate, use arrays that contain elements of the same type. That is, avoid using arrays of union types. Avoid mixed use of integer data and floating-point data in number arrays.
176
177``` TypeScript
178let arrNum: number[] = [1, 1.1, 2];  // Both integer data and floating-point data are used in a value array.
179
180let arrUnion: (number | string)[] = [1, 'hello'];  // Union array.
181```
182
183Place the data of the same type in the same array based on service requirements.
184``` TypeScript
185let arrInt: number[] = [1, 2, 3];
186let arrDouble: number[] = [0.1, 0.2, 0.3];
187let arrString: string[] = ['hello', 'world'];
188```
189
190
191## Exceptions
192
193### Avoiding Frequent Exceptions
194
195Creating exceptions involves constructing the stack frame for the exception, which may performance overhead. In light of this, avoid frequently throwing exceptions in performance-sensitive scenarios, for example, in **for** loop statements.
196
197Before optimization
198
199``` TypeScript
200function div(a: number, b: number): number {
201  if (a <= 0 || b <= 0) {
202    throw new Error('Invalid numbers.')
203  }
204  return a / b
205}
206
207function sum(num: number): number {
208  let sum = 0
209  try {
210    for (let t = 1; t < 100; t++) {
211      sum += div(t, num)
212    }
213  } catch (e) {
214    console.log(e.message)
215  }
216  return sum
217}
218```
219
220After optimization
221
222``` TypeScript
223function div(a: number, b: number): number {
224  if (a <= 0 || b <= 0) {
225    return NaN
226  }
227  return a / b
228}
229
230function sum(num: number): number {
231  let sum = 0
232  for (let t = 1; t < 100; t++) {
233    if (t <= 0 || num <= 0) {
234      console.log('Invalid numbers.')
235    }
236    sum += div(t, num)
237  }
238  return sum
239}
240```
241