# 模å—åŠ è½½å‰¯ä½œç”¨åŠä¼˜åŒ– ## 概述 当使用[ArkTS模å—化](module-principle.md)时,模å—çš„åŠ è½½å’Œæ‰§è¡Œå¯èƒ½ä¼šå¼•å‘**副作用**。副作用指的是模å—导入时除了导出功能或对象之外,é¢å¤–的行为或状æ€å˜åŒ–,**这些行为å¯èƒ½å½±å“程åºçš„其他部分,并导致产生éžé¢„期的顶层代ç 执行ã€å…¨å±€çŠ¶æ€å˜åŒ–ã€åŽŸåž‹é“¾ä¿®æ”¹ã€å¯¼å…¥å†…容未定义ç‰é—®é¢˜**。 ## ArkTS模å—化导致副作用的场景åŠä¼˜åŒ–æ–¹å¼ ### 模å—执行顶层代ç **副作用产生场景** 模å—在被导入时,整个模å—文件ä¸çš„顶层代ç 会立å³æ‰§è¡Œï¼Œè€Œä¸ä»…仅是导出的部分。这æ„味ç€ï¼Œå³ä½¿åªæƒ³ä½¿ç”¨æ¨¡å—ä¸çš„æŸäº›å¯¼å‡ºå†…容,但是任何在顶层作用域ä¸æ‰§è¡Œçš„代ç 也会被è¿è¡Œï¼Œä»Žè€Œäº§ç”Ÿå‰¯ä½œç”¨ã€‚ ```typescript // module.ets console.log("Module loaded!"); // 这段代ç 在导入时会立å³æ‰§è¡Œï¼Œå¯èƒ½ä¼šå¯¼è‡´å‰¯ä½œç”¨ã€‚ export const data = 1; // main.ets import { data } from './module' // 导入时,module.etsä¸çš„console.log会执行,产生输出。 console.log(data); ``` 输出内容: ```typescript Module loaded! 1 ``` **产生的副作用** å³ä½¿åªéœ€è¦data,console.log("Module loaded!") ä»ä¼šè¿è¡Œï¼Œå¯¼è‡´å¼€å‘者å¯èƒ½é¢„期åªè¾“出data的值,但å´é¢å¤–输出了“Module loaded!â€ï¼Œ**å½±å“输出内容**。 **优化方å¼** 优化方å¼1:去除顶层代ç ,åªå¯¼å‡ºéœ€è¦çš„内容,é¿å…ä¸å¿…è¦çš„代ç 执行。 ```typescript // module.ets export const data = 1; // main.ets import { data } from './module' console.log(data); ``` 输出内容: ```typescript 1 ``` 优化方å¼2:将å¯èƒ½å¼•å‘副作用的代ç 放在函数或方法内部,åªæœ‰åœ¨éœ€è¦æ—¶å†æ‰§è¡Œï¼Œè€Œä¸æ˜¯åœ¨æ¨¡å—åŠ è½½æ—¶ç«‹å³æ‰§è¡Œã€‚ ```typescript // module.ets export function initialize() { console.log("Module loaded!"); } export const data = 1; // main.ets import { data } from './module' console.log(data); ``` 输出内容: ```typescript 1 ``` ### 修改全局对象 **副作用产生场景** 顶层代ç 或导入的模å—å¯èƒ½ä¼šç›´æŽ¥**æ“作全局å˜é‡**,从而改å˜å…¨å±€çŠ¶æ€ï¼Œå¼•å‘副作用。 ```typescript // module.ets export let data1 = "data from module" globalThis.someGlobalVar = 100; // 改å˜äº†å…¨å±€çŠ¶æ€ // sideEffectModule.ets export let data2 = "data from side effect module" globalThis.someGlobalVar = 200; // 也å˜äº†å…¨å±€çŠ¶æ€ // moduleUseGlobalVar.ets import { data1 } from './module' // æ¤æ—¶å¯èƒ½é¢„期全局å˜é‡someGlobalVar的值为100 export function useGlobalVar() { console.log(data1); console.log(globalThis.someGlobalVar); // æ¤æ—¶ç”±äºŽmain.etsä¸åŠ 载了sideEffectModule模å—,someGlobalVar的值已ç»è¢«æ”¹ä¸º200 } // main.ets(执行入å£ï¼‰ import { data1 } from "./module" // 将全局å˜é‡someGlobalVar的值改为100 import { data2 } from "./sideEffectModule" // åˆå°†å…¨å±€å˜é‡someGlobalVar的值改为200 import { useGlobalVar } from './moduleUseGlobalVar' useGlobalVar(); function maybeNotCalledAtAll() { console.log(data1); console.log(data2); } ``` 输出内容: ``` data from module 200 ``` **产生的副作用** 模å—åŠ è½½æ—¶ç›´æŽ¥æ”¹å˜å…¨å±€å˜é‡globalThis.someGlobalVar的值,**å½±å“其他使用该å˜é‡çš„模å—或代ç **。 **优化方å¼** å°†å¯èƒ½å¼•å‘副作用的代ç 放在函数或方法内部,åªæœ‰åœ¨éœ€è¦æ—¶å†æ‰§è¡Œï¼Œè€Œä¸æ˜¯åœ¨æ¨¡å—åŠ è½½æ—¶ç«‹å³æ‰§è¡Œã€‚ ```typescript // module.ets export let data1 = "data from module" export function changeGlobalVar() { globalThis.someGlobalVar = 100; } // sideEffectModule.ets export let data2 = "data from side effect module" export function changeGlobalVar() { globalThis.someGlobalVar = 200; } // moduleUseGlobalVar.ets import { data1, changeGlobalVar } from './module' export function useGlobalVar() { console.log(data1); changeGlobalVar(); // 在需è¦çš„时候执行代ç ,而ä¸æ˜¯æ¨¡å—åŠ è½½æ—¶æ‰§è¡Œã€‚ console.log(globalThis.someGlobalVar); } // main.ets(执行入å£ï¼‰ import { data1 } from "./module" import { data2 } from "./sideEffectModule" import { useGlobalVar } from './moduleUseGlobalVar' useGlobalVar(); function maybeNotCalledAtAll() { console.log(data1); console.log(data2); } ``` 输出内容: ``` data from module 100 ``` ### 修改应用级ArkUI组件的状æ€å˜é‡ä¿¡æ¯ **副作用产生场景** 顶层代ç 或导入的模å—å¯èƒ½ä¼šç›´æŽ¥**修改应用级ArkUI组件的状æ€å˜é‡ä¿¡æ¯**,从而改å˜å…¨å±€çŠ¶æ€ï¼Œå¼•å‘副作用。 ```typescript // module.ets export let data = "data from module" AppStorage.setOrCreate("SomeAppStorageVar", 200); // 修改应用全局的UIçŠ¶æ€ // Index.ets import { data } from "./module" // å°†AppStorageä¸çš„SomeAppStorageVar改为200 @Entry @Component struct Index { // å¼€å‘者å¯èƒ½é¢„期该值为100,但是由于module模å—导入,该值已ç»è¢«ä¿®æ”¹ä¸º200,但开å‘者å¯èƒ½å¹¶ä¸çŸ¥é“值已ç»è¢«ä¿®æ”¹ @StorageLink("SomeAppStorageVar") message: number = 100; build() { Row() { Column() { Text("test" + this.message) .fontSize(50) } .width("100%") } .height("100%") } } function maybeNotCalledAtAll() { console.log(data); } ``` 显示内容: ``` test200 ``` **产生的副作用** 模å—åŠ è½½æ—¶ç›´æŽ¥æ”¹å˜AppStorageä¸SomeAppStorageVar的值,**å½±å“其他使用该å˜é‡çš„模å—或代ç **。 ArkUI组件的状æ€å˜é‡ä¿¡æ¯å¯ä»¥é€šè¿‡ä¸€äº›åº”用级接å£ä¿®æ”¹ï¼Œè¯¦è§[ArkUI状æ€ç®¡ç†æŽ¥å£æ–‡æ¡£](../quick-start/arkts-state-management-overview.md)。 **优化方å¼** å°†å¯èƒ½å¼•å‘副作用的代ç 放在函数或方法内部,åªæœ‰åœ¨éœ€è¦æ—¶å†æ‰§è¡Œï¼Œè€Œä¸æ˜¯åœ¨æ¨¡å—åŠ è½½æ—¶ç«‹å³æ‰§è¡Œã€‚ ```typescript // module.ets export let data = "data from module" export function initialize() { AppStorage.setOrCreate("SomeAppStorageVar", 200); } // Index.ets import { data } from "./module" @Entry @Component struct Index { @StorageLink("SomeAppStorageVar") message: number = 100; build() { Row() { Column() { Text("test" + this.message) .fontSize(50) } .width("100%") } .height("100%") } } function maybeNotCalledAtAll() { console.log(data); } ``` 显示内容: ``` test100 ``` ### 修改内置全局å˜é‡æˆ–原型链(ArkTS内ç¦æ¢ä¿®æ”¹å¯¹è±¡åŽŸåž‹ä¸Žå†…置方法) **副作用产生场景** æŸäº›ç¬¬ä¸‰æ–¹åº“或框架å¯èƒ½ä¼šä¿®æ”¹å†…置的全局对象或原型链,以便在较旧的æµè§ˆå™¨æˆ–è¿è¡ŒçŽ¯å¢ƒä¸æ”¯æŒçŽ°ä»£çš„JavaScript特性。这å¯èƒ½ä¼šå½±å“其他代ç çš„è¿è¡Œã€‚ ```typescript // modifyPrototype.ts export let data = "data from modifyPrototype" Array.prototype.includes = function (value) { return this.indexOf(value) !== -1; }; // main.ets import { data } from "./modifyPrototype" // æ¤æ—¶ä¿®æ”¹äº†Array的原型链 let arr = [1, 2, 3, 4]; console.log(arr.includes(1)); // æ¤æ—¶è°ƒç”¨çš„是modifyPrototype.tsä¸çš„Array.prototype.includes方法 function maybeNotCalledAtAll() { console.log(data); } ``` **产生的副作用** 修改内置的全局对象或原型链,影å“其他代ç è¿è¡Œã€‚ **优化方å¼** 导入å¯èƒ½ä¼šä¿®æ”¹å†…置的全局对象或原型链的第三方库时,确认该第三方库的行为是符åˆé¢„期的。 ### 循环ä¾èµ– **副作用产生场景** ArkTS模å—化支æŒå¾ªçŽ¯ä¾èµ–,å³æ¨¡å—Aä¾èµ–模å—B,åŒæ—¶æ¨¡å—Båˆä¾èµ–模å—A。在这ç§æƒ…况下,æŸäº›å¯¼å…¥çš„模å—å¯èƒ½å°šæœªå®Œå…¨åŠ 载,从而导致部分代ç 在执行时行为异常,产生æ„外的副作用。 ```typescript // a.ets import { b } from "./b" console.log('Module A: ', b); export const a = 'A'; // b.ets import { a } from "./a" console.log('Module B: ', a); export const b = 'B'; ``` 输出内容: ``` Error message: a is not initialized Stacktrace: at func_main_0 (b.ets:2:27) ``` **产生的副作用** 由于模å—间相互ä¾èµ–,模å—的执行顺åºå¯èƒ½å¯¼è‡´å¯¼å‡ºçš„内容为空或未定义,影å“代ç 的逻辑æµã€‚ **优化方å¼** å°½é‡é¿å…模å—间的循环ä¾èµ–,确ä¿æ¨¡å—çš„åŠ è½½é¡ºåºæ˜¯æ˜Žç¡®å’Œå¯æŽ§çš„,以é¿å…产生æ„外的副作用。[@security/no-cycle循环ä¾èµ–检查工具](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_no-cycle-V5) å¯ä»¥è¾…助检查循环ä¾èµ–。 ### å»¶è¿ŸåŠ è½½ï¼ˆlazy import)改å˜æ¨¡å—执行顺åºï¼Œå¯èƒ½å¯¼è‡´é¢„期的全局å˜é‡æœªå®šä¹‰ **副作用产生场景** [å»¶è¿ŸåŠ è½½](arkts-lazy-import.md)特性å¯ä½¿å¾…åŠ è½½æ¨¡å—在冷å¯åŠ¨é˜¶æ®µä¸è¢«åŠ 载,直至应用程åºå®žé™…è¿è¡Œè¿‡ç¨‹ä¸éœ€è¦ç”¨åˆ°è¿™äº›æ¨¡å—时,æ‰æŒ‰éœ€åŒæ¥åŠ 载相关模å—,从而缩çŸåº”用冷å¯åŠ¨è€—时。但这也åŒæ—¶ä¼šæ”¹å˜æ¨¡å—的执行顺åºã€‚ ```typescript // module.ets export let data = "data from module" globalThis.someGlobalVar = 100; // moduleUseGlobalVar.ets import lazy { data } from "./module" console.log(globalThis.someGlobalVar); // æ¤æ—¶ç”±äºŽlazy特性,module模å—还未执行,someGlobalVar的值为undefined console.log(data); // 使用到module模å—çš„å˜é‡ï¼Œæ¤æ—¶module模å—执行,someGlobalVar的值å˜ä¸º100 ``` 输出内容: ``` undefined data from module ``` **产生的副作用** ç”±äºŽä½¿ç”¨åˆ°å»¶è¿ŸåŠ è½½ï¼ˆlazy import)特性,会导致模å—å˜é‡åœ¨ä½¿ç”¨åˆ°æ—¶å†æ‰§è¡Œå¯¹åº”的模å—,模å—ä¸çš„一些全局å˜é‡ä¿®æ”¹è¡Œä¸ºä¹Ÿä¼šå»¶è¿Ÿï¼Œå¯èƒ½ä¼šå¯¼è‡´è¿è¡Œç»“æžœä¸ç¬¦åˆé¢„期。 **优化方å¼** å°†å¯èƒ½å¼•å‘副作用的代ç 放在函数或方法内部,åªæœ‰åœ¨éœ€è¦æ—¶å†æ‰§è¡Œï¼Œè€Œä¸æ˜¯åœ¨æ¨¡å—åŠ è½½æ—¶ç«‹å³æ‰§è¡Œã€‚ ```typescript // module.ets export let data = "data from module" export function initialize() { globalThis.someGlobalVar = 100; // 延迟到函数调用时执行 } // moduleUseGlobalVar.ets import lazy { data, initialize } from "./module" initialize(); // 执行åˆå§‹åŒ–函数,åˆå§‹åŒ–someGlobalVar console.log(globalThis.someGlobalVar); // æ¤æ—¶someGlobalVar一定为预期的值 console.log(data); ``` 输出内容: ``` 100 data from module ```