From 986495f48cdf9face699ec62676640d17ebeeaca Mon Sep 17 00:00:00 2001 From: tang jie Date: Wed, 28 May 2025 11:43:41 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=96=B0=E9=9C=80=E6=B1=82]:=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BB=A3=E7=A0=81=E6=8C=87=E5=8D=97=20Issue:=20https:?= =?UTF-8?q?//gitee.com/openharmony/docs/issues/ICB37K?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: tang jie --- .../arkts-utils/arkts-dynamic-import.md | 172 +++++++++---- .../arkts-utils/arkts-module-side-effects.md | 239 ++++++++++++++++-- .../arkts-utils/js-apis-load-native-module.md | 8 + 3 files changed, 350 insertions(+), 69 deletions(-) diff --git a/zh-cn/application-dev/arkts-utils/arkts-dynamic-import.md b/zh-cn/application-dev/arkts-utils/arkts-dynamic-import.md index de12e21a1ae..5aa9b8b0e01 100644 --- a/zh-cn/application-dev/arkts-utils/arkts-dynamic-import.md +++ b/zh-cn/application-dev/arkts-utils/arkts-dynamic-import.md @@ -35,11 +35,13 @@ export function addHarLibrary(a:number, b:number):number { return c; } ``` - + ```typescript // harlibrary's Index.ets -export { Calc, addHarLibrary } from './src/main/ets/utils/Calc' +export { MainPage } from './src/main/ets/components/MainPage' +export { Calc, addHarlibrary } from './src/main/ets/utils/Calc' ``` + ```json5 // HAP's oh-package.json5 @@ -67,7 +69,7 @@ import('harlibrary').then((ns:ESObject) => { ns[functionName](16, 17); // 调用全局方法addHarLibrary() }); ``` - + ## 动态import实现方案介绍 动态import根据入参是常量还是变量,分成动态import常量表达式和动态import变量表达式两大特性规格。 以下是动态import支持的规格列表: @@ -110,6 +112,7 @@ import('harlibrary').then((ns:ESObject) => { return c; } ``` + ```typescript // HAP's src/main/ets/pages/Index.ets @@ -123,6 +126,7 @@ import('harlibrary').then((ns:ESObject) => { console.info(ns.add(3, 5)); } ``` + ```json5 // HAP's oh-package.json5 @@ -148,6 +152,7 @@ import('harlibrary').then((ns:ESObject) => { console.info(ns.add(3, 5)); }); ``` + ```json5 // HAP's oh-package.json5 @@ -166,6 +171,7 @@ import('harlibrary').then((ns:ESObject) => { return c; } ``` + ```typescript // HAP's src/main/ets/pages/Index.ets @@ -173,7 +179,7 @@ import('harlibrary').then((ns:ESObject) => { console.info(ns.add(3, 5)); }); ``` - + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -198,7 +204,7 @@ import('harlibrary').then((ns:ESObject) => { console.info(ns.add(3, 5)); }); ``` - + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -211,9 +217,10 @@ import('harlibrary').then((ns:ESObject) => { ```typescript // HAP's src/main/ets/pages/Index.ets import('@ohos/crypto-js').then((ns:ESObject) => { - console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); + console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.src); }); ``` + ```json5 // HAP's oh-package.json5 @@ -226,10 +233,11 @@ import('harlibrary').then((ns:ESObject) => { ```typescript // HAP's src/main/ets/pages/Index.ets - import('json5').then((ns:ESObject) => { - console.info('DynamicImport json5'); + import('@ohos/hypium').then((ns: ESObject) => { + console.info('DynamicImport @ohos/hypium: ', ns.TestType.FUNCTION.toString()); }); ``` + ```json5 // HAP's oh-package.json5 @@ -248,6 +256,7 @@ import('harlibrary').then((ns:ESObject) => { return c; } ``` + ```typescript // HAP's src/main/ets/pages/Index.ets @@ -255,6 +264,7 @@ import('harlibrary').then((ns:ESObject) => { console.info(ns.add(3, 5)); }); ``` + - **HAP常量动态import自己的Native库** @@ -262,13 +272,16 @@ import('harlibrary').then((ns:ESObject) => { // libnativeapi.so's index.d.ts export const add: (a:number, b:number) => number; ``` + ```typescript // HAP's src/main/ets/pages/Index.ets - import('libnativeapi.so').then((ns:ESObject) => { + import('libentry.so').then((ns:ESObject) => { console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); }); ``` + + ```json5 // HAP's oh-package.json5 @@ -276,17 +289,39 @@ import('harlibrary').then((ns:ESObject) => { "libnativeapi.so": "file:./src/main/cpp/types/libnativeapi" } ``` + - **HAP常量动态import加载API** ```typescript // HAP's src/main/ets/pages/Index.ets - import('@system.app').then((ns:ESObject) => { ns.default.terminate(); }); - import('@system.router').then((ns:ESObject) => { ns.default.clear(); }); - import('@ohos.curves').then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); - import('@ohos.matrix4').then((ns:ESObject) => { ns.default.identity(); }); - import('@ohos.hilog').then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); - ``` + import('libentry.so').then((ns: ESObject) => { + console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); + }); + } else if (item === resourceToString($r('app.string.dynamic_import_system_app'))) { + // HAP常量动态import加载API + import('@system.app').then((ns: ESObject) => { + ns.default.getInfo(); + }); + } else if (item === resourceToString($r('app.string.dynamic_import_ohos_curves'))) { + // HAP常量动态import加载API + import('@ohos.curves').then((ns: ESObject) => { + ns.default.springMotion(0.555, 0.75, 0.001).interpolate(1); + }); + } else if (item === resourceToString($r('app.string.dynamic_import_ohos_matrix4'))) { + // HAP常量动态import加载API + import('@ohos.matrix4').then((ns: ESObject) => { + ns.default.identity().transformPoint([1, 2])[0]; + }); + } else if (item === resourceToString($r('app.string.dynamic_import_ohos_hilog'))) { + // HAP常量动态import加载API + import('@ohos.hilog').then((ns: ESObject) => { + ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); + hilog.info(0x000, 'testTag', '%{public}s', ns.default.LogLevel.DEBUG); + }); + ``` + + ### 动态import变量表达式 @@ -298,18 +333,20 @@ DevEco Studio中模块间的依赖关系通过oh-package.json5中的dependencies 在HAP/HSP/HAR的build-profile.json5中的buildOption中增加runtimeOnly配置项,仅在通过变量动态import时配置,静态import和常量动态import无需配置;并且,通过变量动态import加载API时也无需配置runtimeOnly。如下实例说明如何配置通过变量动态import其他模块,以及变量动态import本模块自己的单文件: ```typescript -// 变量动态import其他模块myhar -let harName = 'myhar'; -import(harName).then((obj: ESObject) => { - console.info('DynamicImport I am a har'); -} - -// 变量动态import本模块自己的单文件src/main/ets/index.ets -let filePath = './Calc'; -import(filePath).then((obj: ESObject) => { - console.info('DynamicImport I am a file'); -} + // 变量动态import其他模块myhar + let harName ='myhar'; + import (harName).then ((ns: ESObject) => { + console.info(ns.add (3, 5)); + }); +} else if (item === resourceToString ($r ('app.string.dynamic_import_module_file'))) { + + // 变量动态 import 本模块自己的单文件 + let filePath = '../utils/Calc'; + import (filePath).then ((ns: ESObject) => { + console.info(ns.add(3, 5)); + }); ``` + 对应的runtimeOnly配置: @@ -341,11 +378,13 @@ import(filePath).then((obj: ESObject) => { ``` ```typescript // HAP's src/main/ets/pages/Index.ets - let packageName = 'myhar'; - import(packageName).then((ns:ESObject) => { + let harPackageName ='myhar'; + import(harPackageName).then((ns: ESObject) => { console.info(ns.add(3, 5)); }); ``` + + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -377,11 +416,13 @@ import(filePath).then((obj: ESObject) => { ``` ```typescript // HAP's src/main/ets/pages/Index.ets - let packageName = 'myHsp'; - import(packageName).then((ns:ESObject) => { + let hspPackageName = 'myHsp'; + import(hspPackageName).then((ns:ESObject) => { console.info(ns.add(3, 5)); }); ``` + + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -405,11 +446,13 @@ import(filePath).then((obj: ESObject) => { ```typescript // HAP's src/main/ets/pages/Index.ets - let packageName = '@ohos/crypto-js'; - import(packageName).then((ns:ESObject) => { - console.info('DynamicImport @ohos/crypto-js: ' + ns.CryptoJS.MD5(123456)); + let remoteHarPackageName = '@ohos/crypto-js'; + import(remoteHarPackageName).then((ns: ESObject) => { + console.info('DynamicImport @ohos/crypto-js:'+ ns.CryptoJS.src); }); ``` + + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -433,11 +476,13 @@ import(filePath).then((obj: ESObject) => { ```typescript // HAP's src/main/ets/pages/Index.ets - let packageName = 'json5'; - import(packageName).then((ns:ESObject) => { - console.info('DynamicImport json5'); + let ohpmPackageName = '@ohos/hypium'; + import (ohpmPackageName).then ((ns: ESObject) => { + console.info('DynamicImport @ohos/hypium:', ns.TestType.FUNCTION.toString()); }); ``` + + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -469,11 +514,13 @@ import(filePath).then((obj: ESObject) => { ``` ```typescript // HAP's src/main/ets/pages/Index.ets - let filePath = '../Calc'; - import(filePath).then((ns:ESObject) => { + let calcFilePath = '../Calc'; + import(calcFilePath).then((ns:ESObject) => { console.info(ns.add(3, 5)); }); ``` + + ```json5 // HAP's build-profile.json5 "buildOption": { @@ -495,11 +542,13 @@ import(filePath).then((obj: ESObject) => { ``` ```typescript // HAP's src/main/ets/pages/Index.ets - let soName = 'libnativeapi.so'; + let soName = 'libentry.so'; import(soName).then((ns:ESObject) => { console.info('DynamicImport libnativeapi.so: ' + ns.default.add(2, 3)); }); ``` + + ```json5 // HAP's oh-package.json5 "dependencies": { @@ -518,22 +567,35 @@ import(filePath).then((obj: ESObject) => { } } ``` - + + - **HAP变量动态import加载API** ```typescript // HAP's src/main/ets/pages/Index.ets - let packageName = '@system.app'; - import(packageName).then((ns:ESObject) => { ns.default.terminate(); }); - packageName = '@system.router'; - import(packageName).then((ns:ESObject) => { ns.default.clear(); }); - packageName = '@ohos.curves'; - import(packageName).then((ns:ESObject) => { ns.default.springMotion(0.555, 0.75, 0.001); }); - packageName = '@ohos.matrix4'; - import(packageName).then((ns:ESObject) => { ns.default.identity(); }); - packageName = '@ohos.hilog'; - import(packageName).then((ns:ESObject) => { ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); }); - ``` + let packageName = '@system.app'; + import (packageName).then ((ns: ESObject) => { + ns.default.getInfo (); + }); + } else if (item === resourceToString($r('app.string.dynamic_import_ohos_curves_variable'))) { + // HAP变量动态import加载API + let packageName = '@ohos.curves'; + import(packageName).then((ns: ESObject) => { + ns.default.springMotion(0.555, 0.75, 0.001).interpolate(1); + }); + } else if (item === resourceToString($r('app.string.dynamic_import_ohos_matrix4_variable'))) { + let packageName = '@ohos.matrix4'; + import (packageName).then ((ns: ESObject) => { + ns.default.identity ().transformPoint ([1, 2])[0]; + }); + } else if (item === resourceToString($r ('app.string.dynamic_import_ohos_hilog_variable'))) { + let packageName = '@ohos.hilog'; + import (packageName).then ((ns: ESObject) => { + ns.default.info(0x0000, 'testTag', '%{public}s', 'DynamicImport @ohos.hilog.'); + }); + ``` + + 变量动态import加载API时无需配置runtimeOnly。 ### HAR模块间动态import依赖解耦 @@ -585,6 +647,8 @@ import(harName).then((ns:ESObject) => { console.info('DynamicImport addHar1 4 + 5 = ' + ns.addHar1(4, 5)); }); ``` + + ```json5 // har1's oh-package.json5 "dependencies": { @@ -607,6 +671,8 @@ import(harName).then((ns:ESObject) => { // har1's Index.ets export { addHar1 } from './src/main/ets/utils/Calc' ``` + + ```typescript // har1's src/main/ets/utils/Calc.ets export function addHar1(a:number, b:number):number { @@ -620,10 +686,13 @@ export function addHar1(a:number, b:number):number { return c; } ``` + ```typescript // har2's Index.ets export { addHar2 } from './src/main/ets/utils/Calc' ``` + + ```typescript // har2's src/main/ets/utils/Calc.ets export function addHar2(a:number, b:number):number { @@ -632,6 +701,7 @@ export function addHar2(a:number, b:number):number { return c; } ``` + har1对har2的依赖dependencies和runtimeOnly配置转移到HAP中,har1不需要配置对har2的dependencies和runtimeOnly配置: diff --git a/zh-cn/application-dev/arkts-utils/arkts-module-side-effects.md b/zh-cn/application-dev/arkts-utils/arkts-module-side-effects.md index 34394ab34dd..ca306b19e94 100644 --- a/zh-cn/application-dev/arkts-utils/arkts-module-side-effects.md +++ b/zh-cn/application-dev/arkts-utils/arkts-module-side-effects.md @@ -30,12 +30,20 @@ Module loaded! 优化方式1:去除顶层代码,只导出需要的内容,避免不必要的代码执行。 ```typescript // module.ets -export const data = 1; +export function initialize() { + console.log("Module loaded!"); +} -// main.ets -import { data } from './module' -console.log(data); +export const dataOptimizeTwo = 1; + +import { data } from './topCodeModule'; // 导入时,module.ets中的console.log会执行,产生输出。 +import { dataOptimizeOne } from './topCodeModuleOptimize'; +import { dataOptimizeTwo } from './module'; ``` + + + + 输出内容: ```typescript 1 @@ -43,15 +51,95 @@ console.log(data); 优化方式2:将可能引发副作用的代码放在函数或方法内部,只有在需要时再执行,而不是在模块加载时立即执行。 ```typescript // module.ets -export function initialize() { - console.log("Module loaded!"); +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 } -export const data = 1; -// main.ets -import { data } from './module' -console.log(data); +//main.ets +import { data1 } from './module'; // 将全局变量someGlobalVar的值改为100 +import { data2 } from './sideEffectModule'; // 又将全局变量someGlobalVar的值改为200 +import { useGlobalVar } from './moduleUseGlobalVar'; +import { dataOptimize1 } from './moduleOptimize'; +import { dataOptimize2 } from './sideEffectModuleOptimize'; +import { useGlobalVarOptimize } from './moduleUseGlobalVarOptimize'; + +function maybeNotCalledAtAll() { + console.log(data1); + console.log(data2); +} +//module.ets +export let data = 'data from module'; + +AppStorage.setOrCreate('SomeAppStorageVar1', 200); // 修改应用全局的UI状态 + +// Index.ets +@Entry +@Component +struct Index { + // 开发者可能预期该值为100,但是由于module模块导入,该值已经被修改为200,但开发者可能并不知道值已经被修改 + @StorageLink('SomeAppStorageVar1') message1: number = 100; + @StorageLink('SomeAppStorageVar2') message2: number = 100; + + build() { + Column() { + Row() { + Text($r('app.string.side_effect')) + .fontSize(30) + .height(30) + Divider() + .vertical(true) + .height(30) + .margin({ left: 8, right: 8 }) + .strokeWidth(2) + Text($r('app.string.optimize')) + .fontSize(30) + .height(30) + } + + Row() { + Text('test' + this.message1) + .fontSize(30) + .height(30) + Divider() + .vertical(true) + .height(30) + .margin({ left: 8, right: 8 }) + .strokeWidth(2) + Text('test' + this.message2) + .fontSize(30) + .height(30) + } + }.width('100%') + } +} + +function maybeNotCalledAtAll() { + console.log(data); +} ``` + + + + + + + + + + + + 输出内容: ```typescript 1 @@ -226,13 +314,69 @@ Array.prototype.includes = function (value) { }; // main.ets -import { data } from "./modifyPrototype" // 此时修改了Array的原型链 -let arr = [1, 2, 3, 4]; -console.log("arr.includes(1) = " + arr.includes(1)); // 此时调用的是modifyPrototype.ts中的Array.prototype.includes方法 -function maybeNotCalledAtAll() { - console.log(data); +import { hilog } from '@kit.PerformanceAnalysisKit'; + +function resourceToString(resource: Resource) { + return getContext().resourceManager.getStringSync(resource); +} + +@Entry +@Component +struct main { + @State message1: ResourceStr = $r('app.string.circular_dependency'); + @State message2: ResourceStr = 'modifyPrototype'; + + build() { + Column() { + Button($r('app.string.circular_dependency')) + .onClick(() => { + import('./a').then((ns: ESObject) => { + hilog.info(0, '[Sample_ModifyingGlobalVariables]', '%{public}s', ns.b); + }).catch((e: Error) => { + hilog.error(0x0000, 'testTag', 'Test Assert error: %{public}s', e.toString()); + this.message1 = resourceToString($r('app.string.circular_dependency')) + 'error: ' + e.toString(); + }) + }) + Row() { + Button('Not Call modifyPrototype') + .width('40%') + .margin({ bottom: 3 }) + .onClick(() => { + let arr = [1, 2, 3, 4]; + console.log(arr.includes(1).toString()); + this.message2 = 'SideEffect: ' + arr.includes(1).toString(); + }) + Divider() + .vertical(true) + .height(30) + .margin({ left: 8, right: 8 }) + .strokeWidth(2) + Button('Call modifyPrototype') + .width('40%') + .margin({ bottom: 3 }) + .onClick(() => { + import('./modifyPrototype').then((es: ESObject) => { + let arr = [1, 2, 3, 4]; + console.log(arr.includes(1).toString()); // 此时调用的是modifyPrototype.ts中的Array.prototype.includes方法 + this.message2 = 'Optimize: ' + arr.includes(1).toString(); + }) // 此时修改了Array的原型链 + }) + } + + Text(this.message1) + .fontSize(20) + Text(this.message2) + .fontSize(20) + } + .height('100%') + .width('100%') + } } ``` + + + + **产生的副作用** 修改内置的全局对象或原型链,影响其他代码运行。 @@ -256,6 +400,10 @@ import { a } from "./a" console.log('Module B: ', a); export const b = 'B'; ``` + + + + 输出内容: ``` Error message: a is not initialized @@ -279,10 +427,65 @@ 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 +import lazy { data } from './module'; +import lazy { dataOptimize, initialize } from './moduleOptimize'; + +@Entry +@Component +struct moduleUseGlobalVar { + @State message1: string = 'SideEffect'; + @State message2: string = 'Optimize'; + + build() { + Column() { + Row() { + Button('LazyImportSideEffect') + .width('40%') + .height(30) + .onClick(() => { + console.log(globalThis.someGlobalVar); // 此时由于lazy特性,module模块还未执行,someGlobalVar的值为undefined + this.message1 = 'SideEffect: ' + globalThis.someGlobalVar; + console.log(data); // 使用到module模块的变量,此时module模块执行,someGlobalVar的值变为100 + }) + Divider() + .vertical(true) + .margin({ left: 8, right: 8 }) + .strokeWidth(3) + .height(30) + Button('LazyImportOptimize') + .width('40%') + .height(30) + .onClick(() => { + initialize(); // 执行初始化函数,初始化someGlobalVar + console.log(globalThis.someGlobalVar); // 此时someGlobalVar一定为预期的值 + this.message2 = 'Optimize: ' + globalThis.someGlobalVar.toString(); + console.log(dataOptimize); + }) + } + + Row() { + Text(this.message1) + .fontSize(20) + .height(30) + Divider() + .vertical(true) + .margin({ left: 8, right: 8 }) + .strokeWidth(3) + .height(30) + Text(this.message2) + .fontSize(20) + .height(30) + } + } + .height('100%') + .width('100%') + } +} ``` + + + + 输出内容: ``` undefined diff --git a/zh-cn/application-dev/arkts-utils/js-apis-load-native-module.md b/zh-cn/application-dev/arkts-utils/js-apis-load-native-module.md index 7e4805bff2a..ff7fdeb2e0c 100644 --- a/zh-cn/application-dev/arkts-utils/js-apis-load-native-module.md +++ b/zh-cn/application-dev/arkts-utils/js-apis-load-native-module.md @@ -33,7 +33,9 @@ loadNativeModule(moduleName: string): Object; ```js let hilog: ESObject = loadNativeModule("@ohos.hilog"); hilog.info(0, "testTag", "loadNativeModule ohos.hilog success"); +this.message = 'loadNativeModule ohos.hilog success' ``` + - **HAP加载Native库** @@ -43,6 +45,8 @@ libentry.so的index.d.ts文件如下: //index.d.ts export const add: (a: number, b: number) => number; ``` + + 1.在加载本地so库时,需在oh-package.json5文件中配置dependencies项。 @@ -53,6 +57,7 @@ export const add: (a: number, b: number) => number; } } ``` + 2.在build-profile.json5中进行配置。 @@ -69,10 +74,13 @@ export const add: (a: number, b: number) => number; } } ``` + 3.使用loadNativeModule加载libentry.so,并调用函数add。 ```js let module: ESObject = loadNativeModule("libentry.so"); let sum: number = module.add(1, 2); +this.message = 'loadNativeModule libentry.so success result: ' + sum.toString(); ``` + -- Gitee