1# 延迟加载(lazy import) 2 3随着应用程序功能的不断扩展,冷启动所需的时间显著增长,主要是由于在启动初期加载了大量模块,其中存在大量未被实际执行的冗余文件。这种情形不仅拖延了应用的初始化过程,还造成了资源的无效占用,亟需采取措施精简加载流程,剔除非必需的文件执行,以优化冷启动性能,确保用户体验的流畅性。 4 5> **说明:** 6> 7> - 延迟加载特性在API12版本开始支持。 8> 9> - 开发者如需在API12上使用lazy import语法,需在工程中配置"compatibleSdkVersionStage": "beta3",否则将无法通过编译。参考[DevEco Studio build-profile.json5配置文件说明](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-hvigor-build-profile-V5#section511142752919)。 10 11 12## 功能特性 13 14延迟加载特性可使待加载文件在冷启动阶段不被加载,直至应用程序实际运行过程中需要用到这些组件时,才按需同步加载相关文件,从而缩短应用冷启动耗时。 15 16## 使用方式 17 18开发者可以利用诸如<!--Del-->[<!--DelEnd-->Trace<!--Del-->](../performance/common-trace-using-instructions.md)<!--DelEnd-->工具或日志记录等手段,来识别冷启动期间未被实际调用的文件<!--RP1-->,分析方法可参考[延迟加载lazy-import使用指导](../performance/Lazy-Import-Instructions.md)<!--RP1End-->。通过对这些数据的分析,开发者能够精准地定位出启动阶段不必预先加载的文件列表。针对这些文件的调用点,可以直接增加lazy标识。但需要注意的是,后续执行的加载是同步加载,有可能会阻塞任务执行(如点击任务,触发了延迟加载,那么运行时会去执行冷启动未加载的文件,从而增加耗时),因此是否使用lazy需要开发者自行评估。 19 20> **说明**: 21> 22> 不推荐开发者盲目增加lazy,同样会增大编译及运行时的识别开销。 23 24## 场景行为解析 25 26- 使用lazy-import延迟加载。 27 28 ```typescript 29 // main.ets 30 import lazy { a } from "./mod1"; // "mod1" 未执行 31 import { c } from "./mod2"; // "mod2" 执行 32 33 // ... 34 35 console.info("main executed"); 36 while (false) { 37 let xx = a; 38 } 39 40 // mod1.ets 41 export let a = "mod1 executed" 42 console.info(a); 43 44 // mod2.ets 45 export let c = "mod2 executed" 46 console.info(c); 47 48 ``` 49 50 执行结果为: 51 52 ```typescript 53 mod2 executed 54 main executed 55 ``` 56 57- 同时对同一模块引用lazy-import与原生import。 58 59 ```typescript 60 // main.ets 61 import lazy { a } from "./mod1"; // "mod1" 未执行 62 import { c } from "./mod2"; // "mod2" 执行 63 import { b } from "./mod1"; // "mod1" 执行 64 65 // ... 66 67 console.info("main executed"); 68 while (false) { 69 let xx = a; 70 } 71 72 // mod1.ets 73 export let a = "mod1 a executed" 74 console.info(a); 75 76 export let b = "mod1 b executed" 77 console.info(b); 78 79 // mod2.ets 80 export let c = "mod2 c executed" 81 console.info(c); 82 83 ``` 84 85 执行结果为: 86 87 ```typescript 88 mod2 c executed 89 mod1 a executed 90 mod1 b executed 91 main executed 92 ``` 93 94 如果在main.ets内删除lazy关键字,执行顺序为: 95 96 ```typescript 97 mod1 a executed 98 mod1 b executed 99 mod2 c executed 100 main executed 101 ``` 102 103## 语法规格 104 105- lazy-import支持如下指令实现: 106 107| 语法 | ModuleRequest | ImportName | LocalName | API12是否支持lazy加载 | 108| :--------------------------------- | :------------ | :---------- | :---------- | :------------------- | 109| import lazy { x } from "mod"; | "mod" | "x" | "x" | 支持 | 110| import lazy { x as v } from "mod"; | "mod" | "x" | "v" | 支持 | 111 112- 延迟加载共享模块或依赖路径内包含共享模块。 113 延迟加载对于共享模块依旧生效,使用限制参考[共享模块开发指导](../arkts-utils/arkts-sendable-module.md)。 114 115### 错误示例 116 117以下写法将引起编译报错。 118 119```typescript 120 export lazy var v; // 编译器提示报错:应用编译报错 121 export lazy default function f(){}; // 编译器提示报错:应用编译报错 122 export lazy default function(){}; // 编译器提示报错:应用编译报错 123 export lazy default 42; // 编译器提示报错:应用编译报错 124 export lazy { x }; // 编译器提示报错:应用编译报错 125 export lazy { x as v }; // 编译器提示报错:应用编译报错 126 export lazy { x } from "mod"; // 编译器提示报错:应用编译报错 127 export lazy { x as v } from "mod"; // 编译器提示报错:应用编译报错 128 export lazy * from "mod"; // 编译器提示报错:应用编译报错 129 130 import lazy v from "mod"; // 编译器提示报错:应用编译报错 131 import lazy * as ns from "mod"; // 编译器提示报错:应用编译报错 132 133``` 134 135与type关键词同时使用将会导致报错。 136 137```typescript 138 import lazy type { obj } from "./mod"; // 不支持,编译器、应用编译报错 139 import type lazy { obj } from "./mod"; // 不支持,编译器、应用编译报错 140 141``` 142 143### 不推荐用法 144 145- 在同一ets文件中,期待延迟加载的依赖模块标记不完全。 146 147 标记不完全将导致延迟加载失效,并且增加识别延迟加载的开销。 148 ```typescript 149 // main.ets 150 import lazy { a } from "./mod1"; // 从"mod1"内获取a对象,标记为延迟加载 151 import { c } from "./mod2"; 152 import { b } from "./mod1"; // 再次获取"mod1"内属性,未标记lazy,"mod1"默认执行 153 154 // ... 155 ``` 156- 在同一ets文件中,未使用懒加载变量并再次导出,不支持延迟加载变量被re-export导出。 157 158 这种方式导出的变量c未在B.ets中使用,文件B.ets不触发执行。在文件A.ets中使用变量c时,该变量未初始化,抛js异常。 159 ```typescript 160 // A.ets 161 import { c } from "./B"; 162 console.info(c); 163 164 // B.ets 165 import lazy { c } from "./C"; // 从"C"内获取c对象,标记为延迟加载 166 export { c } 167 168 // C.ets 169 let c = "c"; 170 export { c } 171 ``` 172 执行结果: 173 ```typescript 174 ReferenceError: c is not initaliized 175 at func_main_0 (A.ets:2:13) 176 ``` 177 178 ```typescript 179 // A_ns.ets 180 import * as ns from "./B"; 181 console.info(ns.c); 182 183 // B.ets 184 import lazy { c } from "./C"; // 从"C"内获取c对象,标记为延迟加载 185 export { c } 186 187 // C.ets 188 let c = "c"; 189 export { c } 190 ``` 191 执行结果: 192 ```typescript 193 ReferenceError: module environment is undefined 194 at func_main_0 (A_ns.js:2:13) 195 ``` 196 197- 暂不支持lazy-import延迟加载kit。 198 199- 开发者需要评估使用延迟加载存在的影响。 200 * 不依赖该模块的执行的side-effect(如初始化全局变量,挂载globalThis等)。 201 * 使用导出对象时,触发延迟加载的耗时导致对应特性的功能劣化。 202 * 使用lazy特性导致模块未执行而导致的bug。 203 204