• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Side Effects and Optimization of Module Loading
2## Overview
3When using [ArkTS modularization](module-principle.md), the process of loading and executing modules may introduce side effects. These side effects refer to additional behavior or state changes that occur when importing a module, beyond simply exporting functions or objects. Such behavior might affect other parts of the program, leading to unintended consequences such as unexpected top-level code execution, global state changes, prototype chain modifications, and undefined imported content.
4
5## Scenarios and Optimization Methods for Side Effects
6### Top-Level Code Execution in Modules
7**Scenario of Side Effects**
8
9When a module is imported, all top-level code within the module file is executed immediately, not just the exported parts. This means that even if only specific exports are needed, any code in the top-level scope will run, potentially causing side effects.
10```typescript
11// module.ets
12console.log("Module loaded!"); // The code is executed immediately upon import, which may cause side effects.
13export const data = 1;
14
15// main.ets
16import { data } from  './module' // When data is imported, the console.log file in module.ets is executed and output is generated.
17console.log(data);
18```
19The output is as follows:
20```typescript
21Module loaded!
221
23```
24**Side effects produced**
25
26Even though only **data** is required, **console.log("Module loaded!")** still runs, causing the unexpected output of "Module loaded!" in addition to the value of **data**.
27
28**Optimized methods**
29
30Optimization method 1: Remove the top-level code and export only the required content to avoid unnecessary code execution.
31```typescript
32// module.ets
33export const data = 1;
34
35// main.ets
36import { data } from  './module'
37console.log(data);
38```
39The output is as follows:
40```typescript
411
42```
43Optimization method 2: Encapsulate code that may cause side effects within functions or methods, and execute the code only when needed, rather than upon module loading.
44```typescript
45// module.ets
46export function initialize() {
47    console.log("Module loaded!");
48}
49export const data = 1;
50
51// main.ets
52import { data } from  './module'
53console.log(data);
54```
55The output is as follows:
56```typescript
571
58```
59### Modifying Global Objects
60**Scenario of side effects**
61
62The top-level code or imported modules may directly manipulate global variables, thereby changing the global state and causing side effects.
63```typescript
64// module.ets
65export let data1 = "data from module"
66globalThis.someGlobalVar = 100; // The global state is changed.
67
68// sideEffectModule.ets
69export let data2 = "data from side effect module"
70globalThis.someGlobalVar = 200; // The global state is changed.
71
72// moduleUseGlobalVar.ets
73import { data1 } from './module' // The expected value of the global variable someGlobalVar is 100.
74export function useGlobalVar() {
75    console.log(data1);
76    console.log(globalThis.someGlobalVar); // The value of someGlobalVar is changed to 200 because the sideEffectModule module is loaded to main.ets.
77}
78
79// main.ets (entry point)
80import { data1 } from "./module" // The value of the global variable someGlobalVar is changed to 100.
81import { data2 } from "./sideEffectModule" // The value of the global variable someGlobalVar is changed to 200.
82import { useGlobalVar } from './moduleUseGlobalVar'
83
84useGlobalVar();
85function maybeNotCalledAtAll() {
86    console.log(data1);
87    console.log(data2);
88}
89```
90The output is as follows:
91```
92data from module
93200
94```
95**Side effects produced**
96
97Modules directly change the value of the **global variable globalThis.someGlobalVar**, affecting other modules or code that depends on this variable.
98
99**Optimized methods**
100
101Encapsulate code that may cause side effects within functions or methods, and execute the code only when needed, rather than upon module loading.
102```typescript
103// module.ets
104export let data1 = "data from module"
105export function changeGlobalVar() {
106    globalThis.someGlobalVar = 100;
107}
108
109// sideEffectModule.ets
110export let data2 = "data from side effect module"
111export function changeGlobalVar() {
112    globalThis.someGlobalVar = 200;
113}
114
115// moduleUseGlobalVar.ets
116import { data1, changeGlobalVar } from './module'
117export function useGlobalVar() {
118    console.log(data1);
119    changeGlobalVar(); // Execute the code when needed, not upon module loading.
120    console.log(globalThis.someGlobalVar);
121}
122
123// main.ets (entry point)
124import { data1 } from "./module"
125import { data2 } from "./sideEffectModule"
126import { useGlobalVar } from './moduleUseGlobalVar'
127
128useGlobalVar();
129function maybeNotCalledAtAll() {
130    console.log(data1);
131    console.log(data2);
132}
133```
134The output is as follows:
135```
136data from module
137100
138```
139### Modifying State Variables of Application-level ArkUI Components
140**Scenario of side effects**
141
142The top-level code or imported modules may directly modify the state variables of application-level ArkUI components, thereby changing the global state and causing side effects.
143```typescript
144// module.ets
145export let data = "data from module"
146AppStorage.setOrCreate("SomeAppStorageVar", 200); // The global UI state of the application is changed.
147
148// Index.ets
149import { data } from "./module" // SomeAppStorageVar in AppStorage is changed to 200.
150
151@Entry
152@Component
153struct Index {
154    // The expected value is 100. However, the value has been changed to 200 due to module import.
155    @StorageLink("SomeAppStorageVar") message: number = 100;
156    build() {
157        Row() {
158            Column() {
159                Text("test" + this.message)
160                    .fontSize(50)
161            }
162            .width("100%")
163        }
164        .height("100%")
165    }
166}
167function maybeNotCalledAtAll() {
168    console.log(data);
169}
170```
171The following content is displayed:
172```
173test200
174```
175**Side effects produced**
176
177Modules directly change the value of **SomeAppStorageVar** in AppStorage, affecting other modules or code that depends on this variable.
178
179For more information on modifying ArkUI component state variables, see [State Management Overview](../ui/state-management/arkts-state-management-overview.md).
180
181**Optimized methods**
182
183Encapsulate code that may cause side effects within functions or methods, and execute the code only when needed, rather than upon module loading.
184```typescript
185// module.ets
186export let data = "data from module"
187export function initialize() {
188    AppStorage.setOrCreate("SomeAppStorageVar", 200);
189}
190
191// Index.ets
192import { data } from "./module"
193
194@Entry
195@Component
196struct Index {
197    @StorageLink("SomeAppStorageVar") message: number = 100;
198    build() {
199        Row() {
200            Column() {
201                Text("test" + this.message)
202                    .fontSize(50)
203            }
204            .width("100%")
205        }
206        .height("100%")
207    }
208}
209function maybeNotCalledAtAll() {
210    console.log(data);
211}
212```
213The following content is displayed:
214```
215test100
216```
217### Modifying Built-in Global Variables or Prototype Chains (Modifying Object Prototypes or Built-in Methods Is Forbidden in ArkTS)
218**Scenario of side effects**
219
220To support modern JavaScript features in old browsers or runtime environments, third-party libraries or frameworks may modify built-in global objects or prototype chains. This can affect the execution of other code.
221```typescript
222// modifyPrototype.ts
223export let data = "data from modifyPrototype"
224Array.prototype.includes = function (value) {
225    return this.indexOf(value) !== -1;
226};
227
228// main.ets
229import { data } from "./modifyPrototype" // The prototype chain of the array is modified.
230let arr = [1, 2, 3, 4];
231console.log("arr.includes(1) = " + arr.includes(1)); // The Array.prototype.includes method in modifyPrototype.ts is called.
232function maybeNotCalledAtAll() {
233    console.log(data);
234}
235```
236**Side effects produced**
237
238Modifying built-in global objects or prototype chains affects the execution of other code.
239
240**Optimized methods**
241
242When importing third-party libraries that may modify built-in global objects or prototype chains, ensure that the behavior of the third-party library is as expected.
243### Circular Dependencies
244
245**Scenario of side effects**
246
247ArkTS modularization supports circular dependencies, where module A depends on module B, and module B depends on module A. In such cases, some imported modules may not be fully loaded, leading to abnormal behavior and unintended side effects during execution.
248```typescript
249// a.ets
250import { b } from "./b"
251console.log('Module A: ', b);
252export const a = 'A';
253
254// b.ets
255import { a } from "./a"
256console.log('Module B: ', a);
257export const b = 'B';
258```
259The output is as follows:
260```
261Error message: a is not initialized
262Stacktrace:
263    at func_main_0 (b.ets:2:27)
264```
265**Side effects produced**
266
267Due to mutual dependencies between modules, the execution order of modules may result in undefined exports, affecting the logic flow of the code. The specific error message is "Variable name is not initialized."
268
269**Optimized methods**
270
271Avoid circular dependencies between modules whenever possible, and ensure that the loading order of modules is clear and controllable to prevent unexpected side effects. You can use [@security/no-cycle](https://developer.huawei.com/consumer/en/doc/harmonyos-guides/ide_no-cycle) when detecting circular dependencies.
272### Lazy Import Changing the Module Execution Sequence and Leading to Undefined Global Variables
273**Scenario of side effects**
274
275The [Lazy Import](arkts-lazy-import.md) feature allows modules to be loaded on-demand during the application runtime, rather than during the cold start phase, thereby reducing the cold start time. However, this also changes the execution sequence of modules.
276```typescript
277// module.ets
278export let data = "data from module"
279globalThis.someGlobalVar = 100;
280
281// moduleUseGlobalVar.ets
282import lazy { data } from "./module"
283console.log(globalThis.someGlobalVar); // The module is not executed due to lazy import. The value of someGlobalVar is undefined.
284console.log(data); // During the value of the variable, the module is executed and the value of someGlobalVar changes to 100.
285```
286The output is as follows:
287```
288undefined
289data from module
290```
291**Side effects produced**
292
293Using the lazy import feature delays the execution of modules until they are needed. Modifications to global variables within these modules are also delayed, potentially leading to unexpected results.
294
295**Optimized methods**
296
297Encapsulate code that may cause side effects within functions or methods, and execute the code only when needed, rather than upon module loading.
298```typescript
299// module.ets
300export let data = "data from module"
301export function initialize() {
302    globalThis.someGlobalVar = 100; // Delay the execution until the function is called.
303}
304
305// moduleUseGlobalVar.ets
306import lazy { data, initialize } from "./module"
307initialize(); // Execute the initialization function to initialize someGlobalVar.
308console.log(globalThis.someGlobalVar); // someGlobalVar will have the expected value.
309console.log(data);
310```
311The output is as follows:
312```
313100
314data from module
315```
316