1# ArkTS Performant Programming Practices 2 3## Overview 4 5 6This 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). 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 Integer Variables and Floating-point Variables of the number Type 20 21For the **number** type, integer data and floating-point data are distinguished during optimization. Avoiding change of the data type after initialization is recommended. 22 23``` TypeScript 24let intNum = 1; 25intNum = 1.1; // This variable is declared as the integer data. You are advised not to change it to the floating-point data. 26 27let doubleNum = 1.1; 28doubleNum = 1; // This variable is declared as the floating-point data. You are advised not to change it to the integer data. 29``` 30 31 32### Avoiding Overflow in Arithmetic Operations 33 34When 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: 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 43Constants 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. 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 for 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 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: 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 invariants 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## Function 83 84### Using Parameter to Pass External Variables 85 86Closures 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. 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 112The 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. 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## Array 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 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. 161 162``` TypeScript 163// Allocate an array of 100000 bytes and use a hash table to store elements when running. 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 Union Arrays 174 175Avoid using union arrays. Avoid mixed use of integer data and floating-point data in value arrays. 176 177``` TypeScript 178let arrNum: number[] = [1, 1.1, 2]; // Use both integer data and floating-point data 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## Exception 192 193### Avoiding Frequent Exceptions 194 195When 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. 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