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