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