1# 应用性能优化常见问题解决指导
2
3## 概述
4
5本文总结了实际开发应用时常见的性能优化规范,配合举例实际开发中常见的正反例代码,帮助开发者解决大部分性能问题。
6
7### 性能规范总览目录
8| &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  &emsp;&emsp;  &emsp;&emsp; <br />分类<br />&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; &emsp;&emsp;&emsp;&emsp;  &emsp;&emsp;   |<br />高频程度 (5满分)<br />&emsp;&emsp;&emsp;&emsp;   | 规范(检查项)       | 实操方法                |            <br />代码示例<br />&emsp;&emsp;&emsp;&emsp;                 |
9|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------:|:---------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------:|
10| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          5                          | 不建议在aboutToAppear(),aboutToDisappear()等生命周期中执行耗时操作 | 排查所有的aboutToAppear和aboutToDisappear函数(或者通过Trace查看),查看是否有耗时操作,改为setTimeOut或者在TaskPool中执行。                                          |       [代码示例](#不建议在abouttoappearabouttodisappear等生命周期中执行耗时操作)        |
11| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          5                          | 不要在回调函数中执行耗时操作(ArkUI接口回调、网络访问回调、await等)            | 排查所有的回调函数(或者通过Trace查看),尤其是ArkUI接口,网络回调函数,查看是否有耗时操作,是否使用了await操作,改为setTimeOut或者在TaskPool中执行。                      |            [代码示例](#不要在回调函数中执行耗时操作arkui接口回调网络访问回调await等)             |
12| 响应时延&nbsp;/&nbsp;完成时延&nbsp;/&nbsp;帧率                                                                                                                                     |                          5                          | 列表场景未使用LazyForEach+组件复用+缓存列表项            | 排查使用LazyForEach的代码,确认是否有使用组件复用(@Reusable)+缓存列表项(cachedCount)。                                                                                                           |                [代码示例](#列表场景未使用lazyforeach组件复用缓存列表项)                 |
13| 完成时延                                                                                                                                                                     |                          5                          | Web未使用预连接,未提前初始化引擎    | 在应用创建Ability的时候,在OnCreate阶段预先初始化内核,建议把引擎的初始化放在setTimeOut中。                                                                                                              |                     [代码示例](#web未使用预连接未提前初始化引擎)                      |
14| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          5                          | 高频接口中不要打印Trace和日志    | 排查接口onTouch、onItemDragMove、onDragMove、onDidScroll、onMouse、onVisibleAreaChange、OnAreaChange、onActionUpdate、animator的onFrame、组件复用场景下的aboutToReuse,不建议在里面打印trace和日志。          |                     [代码示例](#高频接口中不要打印trace和日志)                      |
15| 完成时延&nbsp;/&nbsp;帧率                                                                                                                                                      |                          4                          | 组件复用里面有if语句,但是未使用reuseId            | 排查使用了@Reusable的自定义组件,查看build中给是否使用了if/else或ForEach等条件渲染语句,如果使用了,需要配合reuseId一起使用。                                                                                        |                  [代码示例](#组件复用里面有if语句但是未使用reuseid)                   |
16| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          4                          | 不建议使用@Prop装饰器           | 全局搜索@Prop并且替换                                                                                                                                           |                        [代码示例](#不建议使用prop装饰器)                        |
17| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          3                          | 避免在ResourceManager的getXXXSync接口入参中直接使用资源信息           | 排查ResourceManager.getXXXSync接口,查看入参时需要使用getStringSync($r('app.media.icon').id)的形式,如果未使用需要整改。                                                 | [代码示例](#避免在resourcemanager的getxxxsync接口入参中直接使用资源信息) |
18| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          3                          | 展示用的自定义组件(数据从父组件中获取,无独立数据处理)使用@Builder替换           | 审视@Component标记的自定义组件,如果里面没有独立的生命周期处理逻辑,数据由父组件传递,建议@Builder替代。                                                           |            [代码示例](#展示用的自定义组件数据从父组件中获取无独立数据处理使用builder替换)            |
19| 响应时延&nbsp;/&nbsp;完成时延&nbsp;/&nbsp;帧率                                                                                                                                     |                          3                          | 删除无具体逻辑的生命周期,ArkUI的函数回调等,删除冗余堵塞日志打印           | 排查所有的aboutToAppear、aboutToDisappear等生命周期函数,排查ArkUI的回调函数,如果函数中无具体业务逻辑,例如只打印了日志,删除函数回调。                                        |             [代码示例](#删除无具体逻辑的生命周期arkui的函数回调等删除冗余堵塞日志打印)              |
20| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          3                          | 删除未关联组件的状态变量装饰器           | 排查全局的状态变量装饰器,如果变量未关联组件,删除装饰器。             |                      [代码示例](#删除未关联组件的状态变量装饰器)                       |
21| 帧率                                                                                                                                                                       |                          2                          | 	crypto-js性能差           | 排查buffer.from关键字,加密建议使用原生的cryptoFramework,然后将buffer替换为base64helper,性能提升10倍以上, 且数据量越大越明显。             |                        [代码示例](#crypto-js性能差)                        |
22| 响应时延&nbsp;/&nbsp;完成时延                                                                                                                                                    |                          1                          | 	不建议使用Marquee组件           | 排查Marquee关键字,使用Text的跑马灯模式(TextOverflow.MARQUEE)替代。             |                       [代码示例](#不建议使用marquee组件)                       |
23| 完成时延                                                                                                                                                                     |                          1                          | 	不能使用函数作为ArkUI组件的属性和组件复用的自定义组件的入参           | 查看属性是否有xx()函数写法,确认函数/方法中是否有耗时操作,替换成变量。            |              [代码示例](#不能使用函数作为arkui组件的属性和组件复用的自定义组件的入参)              |
24| 完成时延                                                                                                                                                                     |                          1                          | 	不建议使用.linearGradient颜色渐变属性           | 排查linearGradient关键字,可以使用图片代替。            |                 [代码示例](#不建议使用lineargradient颜色渐变属性)                  |
25| 完成时延&nbsp;/&nbsp;帧率                                                                                                                                                      |                          1                          | 	不要在for/while循环中执行耗时操作           | 排查for/while循环,查看里面是否有打印日志或者Trace。            |                    [代码示例](#不要在forwhile循环中执行耗时操作)                    |
26| 完成时延&nbsp;/&nbsp;帧率                                                                                                                                                      |                          1                          | 	变量初值不建议设置为undefined,需进行默认初始化           | 例如number设置为0,string设置为空字符串等,这样在使用过程中更不需要增加额外判空。排查类中的变量,看看是否有初始化为undefined。            |                [代码示例](#变量初值不建议设置为undefined需进行默认初始化)                 |
27
28## 性能优化规范
29
30### 不建议在aboutToAppear()、aboutToDisappear()等生命周期中执行耗时操作
31#### 类型
32响应时延/完成时延
33#### 解决方法
34排查所有的aboutToAppear和aboutToDisappear函数(或者通过Trace查看),查看是否有耗时操作,改为setTimeOut或者在TaskPool中执行。
35
36#### 反例
37```typescript
38@Entry
39@Component
40struct ViewA {
41  @State private text: string = "";
42  private count: number = 0;
43  // 反例:在aboutToAppear接口中执行耗时操作,阻塞页面绘制。
44  aboutToAppear() {
45    // 耗时操作
46    this.computeTask();
47    let context = context.resourceManager.getStringSync($r('app.string.startup_text'));
48  }
49
50  computeTask(): void {
51    this.count = 0;
52    while (this.count < LARGE_NUMBER) {
53    this.count++;
54  }
55  let context = getContext(this) as Context;
56  this.text = context.resourceManager.getStringSync($r('app.string.task_text'));
57}
58}
59```
60#### 正例
61```typescript
62@Entry
63@Component
64struct ViewB {
65  @State private text: string = "";
66  private count: number = 0;
67  private readonly DELAYED_TIME: number = 2000; // 定时器设置延时2s
68
69  // 正例:在aboutToAppear接口中对耗时间的计算任务进行了异步处理。
70  aboutToAppear() {
71    // 耗时操作
72    this.computeTaskAsync(); // 异步任务
73    let context = getContext(this) as Context;
74    this.text = context.resourceManager.getStringSync($r('app.string.startup_text'));
75  }
76
77  computeTask(): void {
78    this.count = 0;
79    while (this.count < LARGE_NUMBER) {
80    this.count++;
81  }
82  let context = getContext(this) as Context;
83  this.text = context.resourceManager.getStringSync($r('app.string.task_text'));
84}
85
86// 运算任务异步处理
87private computeTaskAsync(): void {
88  setTimeout(() => {
89  // 这里使用setTimeout来实现异步延迟运行
90  this.computeTask();
91  }, DELAYED_TIME)
92}
93}
94```
95#### 高频程度&收益(5满分)
965
97
98### 不要在回调函数中执行耗时操作(ArkUI接口回调、网络访问回调、await等)
99#### 类型
100响应时延/完成时延
101#### 解决方法
102排查所有的回调函数(或者通过Trace查看),尤其是ArkUI接口,网络回调函数,查看是否有耗时操作,是否使用了await操作,改为setTimeOut或者在TaskPool中执行。
103#### 反例
104```typescript
105import http from '@ohos.net.http';
106
107async aboutToAppear() {
108  // ...
109  const b = await http.createHttp();
110}
111```
112#### 正例
113```typescript
114aboutToAppear() {
115  // ...
116  // 在生命周期中,使用TaskPool加载和解析网络数据
117  this.requestByTaskPool();
118}
119
120@Concurrent
121getInfoFromHttp(): string[] {
122  // 从网络加载数据
123  return http.request();
124}
125
126requestByTaskPool(): void {
127  // 创建任务项
128  let task: taskpool.Task = new taskpool.Task(this.getInfoFromHttp);
129  try {
130  // 执行网络加载函数
131  taskpool.execute(task, taskpool.Priority.HIGH).then((res: string[]) => {
132});
133} catch (err) {
134  logger.error(TAG, "failed, " + (err as BusinessError).toString());
135}
136}
137```
138#### 高频程度&收益(5满分)
1395
140
141### 列表场景未使用LazyForEach+组件复用+缓存列表项
142#### 类型
143响应时延/完成时延/帧率
144#### 解决方法
145排查使用LazyForEach的代码,确认是否有使用组件复用(@Reusable)+缓存列表项(cachedCount)。
146#### 反例
147```typescript
148struct GoodView {
149  build() {
150    Grid() {
151      // 未使用LazyForEach+组件复用+缓存列表项
152      ForEach(this.GoodDataOne, (item, index) => {
153        GridItem() {
154          Column() {
155            Image(item.img)
156              .height(item.hei)
157              .width('100%')
158              .objectFit(ImageFit.Fill)
159
160            Text(item.introduce)
161              .fontSize(14)
162              .padding({ left: 5, right: 5 })
163              .margin({ top: 5 })
164            Row() {
165              Row() {
166                Text('¥')
167                  .fontSize(10)
168                  .fontColor(Color.Red)
169                  .baselineOffset(-4)
170                Text(item.price)
171                  .fontSize(16)
172                  .fontColor(Color.Red)
173                Text(item.numb)
174                  .fontSize(10)
175                  .fontColor(Color.Gray)
176                  .baselineOffset(-4)
177                  .margin({ left: 5 })
178              }
179
180              Image($r('app.media.photo63'))
181                .width(20)
182                .height(10)
183                .margin({ bottom: -8 })
184            }
185            .width('100%')
186              .justifyContent(FlexAlign.SpaceBetween)
187              .padding({ left: 5, right: 5 })
188              .margin({ top: 15 })
189          }
190          .borderRadius(10)
191            .backgroundColor(Color.White)
192            .clip(true)
193            .width('100%')
194            .height(290)
195        }
196      }, (item) => JSON.stringify(item))
197    }
198  }
199}
200```
201#### 正例
202```typescript
203// 组件复用
204@Reusable
205@Component
206struct GoodItems {
207  @State img: Resource = $r("app.media.photo61");
208  @State webImg?: string = '';
209  @State hei: number = 0;
210  @State introduce: string = '';
211  @State price: string = '';
212  @State numb: string = '';
213  @LocalStorageLink('storageSimpleProp') simpleVarName: string = '';
214  isOnclick: boolean = true;
215  index: number = 0;
216  controllerVideo: VideoController = new VideoController();
217
218  aboutToReuse(params)
219  {
220    this.webImg = params.webImg;
221    this.img = params.img;
222    this.hei = params.hei;
223    this.introduce = params.introduce;
224    this.price = params.price;
225    this.numb = params.numb;
226  }
227
228  build() {
229    Grid(){
230      // 懒加载
231      LazyForEach(this.GoodDataOne, (item, index) => {
232        GridItem() {
233          GoodItems({
234            isOnclick:item.data.isOnclick,
235            img:item.data.img,
236            webImg:item.data.webImg,
237            hei:item.data.hei,
238            introduce:item.data.introduce,
239            price:item.data.price,
240            numb:item.data.numb,
241            index:index
242          })
243            .reuseId(this.CombineStr(item.type))
244        }
245      }, (item) => JSON.stringify(item))
246    }.cachedCount(2) // 缓存列表项
247  }
248}
249```
250#### 高频程度&收益(5满分)
2515
252
253### Web未使用预连接,未提前初始化引擎
254#### 类型
255完成时延
256#### 解决方法
257在应用创建Ability的时候,在OnCreate阶段预先初始化内核,建议把引擎的初始化放在setTimeOut中。
258#### 反例
259```typescript
260// Web组件引擎没有初始化,且沒有使用预连接
261export default class EntryAbility extends UIAbility {
262  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
263    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
264  }
265}
266controller: webview.WebviewController = new webview.WebviewController();
267// ...
268Web({ src: 'https://www.example.com', controller: this.controller })
269
270```
271#### 正例
272```typescript
273export default class EntryAbility extends UIAbility {
274  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
275    console.info("EntryAbility onCreate")
276    // 在 Web 组件初始化之前,通过此接口加载 Web 引擎的动态库文件,以提高启动性能。
277    setTimeout(() => {
278      // 这里使用setTimeout来实现延迟运行
279      web_webview.WebviewController.initializeWebEngine()
280    }, 200)
281    console.info("EntryAbility onCreate done");
282  }
283}
284
285controller: webview.WebviewController = new webview.WebviewController();
286// ...
287Web({ src: 'https://www.example.com', controller: this.controller })
288
289```
290#### 高频程度&收益(5满分)
2915
292
293### 高频接口中不要打印Trace和日志
294#### 类型
295响应时延/完成时延
296#### 解决方法
297排查接口onTouch、onItemDragMove、onDragMove、onDidScroll、onMouse、onVisibleAreaChange、OnAreaChange、
298onActionUpdate、animator的onFrame、组件复用场景下的aboutToReuse,不建议在里面打印trace和日志。
299#### 反例
300```typescript
301import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
302
303@Component
304struct CounterOfOnDidScroll {
305  private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
306
307  build() {
308    Scroll() {
309      ForEach(this.arr, (item: number) => {
310        Text("ListItem" + item)
311          .width("100%")
312          .height("100%")
313      }, (item: number) => item.toString())
314    }
315    .width('100%')
316    .height('100%')
317    .onDidScroll(() => {
318      hiTraceMeter.startTrace("ScrollSlide", 1002);
319      // 业务逻辑
320      // ...
321      // 在高频接口中不建议打印Trace和日志
322      hiTraceMeter.finishTrace("ScrollSlide", 1002);
323    })
324  }
325```
326#### 正例
327```typescript
328@Component
329struct PositiveOfOnDidScroll {
330  private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
331
332  build() {
333    Scroll() {
334      List() {
335        ForEach(this.arr, (item: number) => {
336          ListItem() {
337            Text("TextItem" + item)
338          }.width("100%")
339           .height(100)
340        }, (item: number) => item.toString())
341      }
342      .divider({ strokeWidth: 3, color: Color.Gray })
343    }
344    .width('100%')
345    .height('100%')
346    .onDidScroll(() => {
347      // 业务逻辑
348      // ...
349    })
350  }
351}
352```
353#### 高频程度&收益(5满分)
3544
355
356### 组件复用里面有if语句,但是未使用reuseId
357#### 类型
358完成时延/帧率
359#### 解决方法
360排查使用了@Reusable的自定义组件,查看build中给是否使用了if/else或ForEach等条件渲染语句,如果使用了,需要配合reuseId一起使用。
361#### 反例
362```typescript
363@Component
364@Reusable
365export struct MockComplexSubBranch {
366  @State alignStyle: FlexAlign = FlexAlign.Center;
367
368  aboutToReuse(params: Record<string, number>): void { // 缓存复用组件,更新组件的状态变量
369    this.alignStyle = params.alignStyle;
370  }
371
372  build() {
373    Column() {
374      Column({ space: 5 }) {
375        Text('ComplexSubBranch not reusable')
376          .fontSize($r('app.integer.font_size_9'))
377          .fontColor($r('app.color.hint_txt_color'))
378          .width($r('app.string.layout_90_percent'))
379      }
380    }
381  }
382}
383
384import { MockComplexSubBranch } from './MockComplexSubBranch';
385
386@Component
387export struct WithoutReuseId {
388  @State isAlignStyleStart: boolean = true;
389
390  build() {
391    Column() {
392      Button("Change FlexAlign")
393        .onClick(() => {
394          this.isAlignStyleStart = !this.isAlignStyleStart;
395        })
396      Stack() {
397        if (this.isAlignStyleStart) {
398          MockComplexSubBranch({ alignStyle: FlexAlign.Start }); // 未使用reuseId
399        } else {
400          MockComplexSubBranch({ alignStyle: FlexAlign.End });
401        }
402      }
403    }
404  }
405}
406```
407#### 正例
408```typescript
409@Component
410@Reusable
411// 添加Reusable装饰器,声明组件具备可复用的能力
412export struct MockComplexSubBranch {
413  @State alignStyle: FlexAlign = FlexAlign.Center;
414
415  aboutToReuse(params: Record<string, number>): void {
416    this.alignStyle = params.alignStyle;
417  }
418
419  build() {
420    Column() {
421      Column({ space: 5 }) {
422        Text('ComplexSubBranch reusable')
423          .fontSize($r('app.integer.font_size_9'))
424          .fontColor($r('app.color.hint_txt_color'))
425          .width($r('app.string.layout_90_percent'))
426      }
427    }
428  }
429}
430
431import { MockComplexReusableSubBranch } from './MockComplexReusableSubBranch';
432
433@Component
434export struct WithReuseId {
435  @State isAlignStyleStart: boolean = true;
436
437  build() {
438    Column() {
439      Button("Change FlexAlign")
440        .onClick(() => {
441          this.isAlignStyleStart = !this.isAlignStyleStart;
442        })
443      Stack() {
444        if (this.isAlignStyleStart) {
445          MockComplexSubBranch({ alignStyle: FlexAlign.Start }).reuseId("MockComplexSubBranchStart"); // 使用reuseId标识
446        } else {
447          MockComplexSubBranch({ alignStyle: FlexAlign.End }).reuseId("MockComplexSubBranchEnd");
448        }
449      }
450    }
451  }
452}
453```
454
455#### 高频程度&收益(5满分)
4564
457
458### 不建议使用@Prop装饰器
459#### 类型
460响应时延/完成时延
461#### 解决方法
462全局搜索@Prop并且替换。
463#### 反例
464```typescript
465@Observed
466class Book {
467  public c: number = 0;
468
469  constructor(c: number) {
470    this.c = c;
471  }
472}
473
474@Component
475struct PropChild {
476  @Prop testNum: Book; // @Prop装饰状态变量会深拷贝
477
478  build() {
479    Text(`PropChild testNum ${this.testNum.c}`)
480  }
481}
482
483@Entry
484@Component
485struct Parent1 {
486  @State testNum: Book[] = [new Book(1)];
487
488  build() {
489    Column() {
490      Text(`Parent testNum ${this.testNum[0].c}`)
491        .onClick(() => {
492          this.testNum[0].c += 1;
493        })
494      // PropChild没有改变@Prop testNum: Book的值,所以这时最优的选择是使用@ObjectLink
495      PropChild({ testNum: this.testNum[0] })
496    }
497  }
498}
499```
500#### 正例
501```typescript
502@Observed
503class Book {
504  public c: number = 0;
505
506  constructor(c: number) {
507    this.c = c;
508  }
509}
510
511@Component
512struct PropChild {
513  @ObjectLink testNum: Book; // @ObjectLink装饰状态变量不会深拷贝
514
515  build() {
516    Text(`PropChild testNum ${this.testNum.c}`)
517  }
518}
519
520@Entry
521@Component
522struct Parent2 {
523  @State testNum: Book[] = [new Book(1)];
524
525  build() {
526    Column() {
527      Text(`Parent testNum ${this.testNum[0].c}`)
528        .onClick(() => {
529          this.testNum[0].c += 1;
530        })
531      // 当子组件不需要发生本地改变时,优先使用 @ObjectLink,因为@Prop是会深拷贝数据,具有拷贝的性能开销,所以这个时候@ObjectLink是比@Link和 @Prop更优的选择
532      PropChild({ testNum: this.testNum[0] })
533    }
534  }
535}
536```
537#### 高频程度&收益(5满分)
5384
539
540### 避免在ResourceManager的getXXXSync接口入参中直接使用资源信息
541#### 类型
542响应时延/完成时延
543#### 解决方法
544排查ResourceManager.getXXXSync接口,查看入参时需要使用getStringSync($r('app.media.icon').id)的形式,
545如果未使用需要整改。
546
547#### 反例
548```typescript
549this.context.resourceManager.getStringSync($r('app.string.test'));
550```
551#### 正例
552```typescript
553this.context.resourceManager.getStringSync($r('app.string.test').id);
554```
555#### 高频程度&收益(5满分)
5563
557
558### 展示用的自定义组件(数据从父组件中获取,无独立数据处理)使用@Builder替换
559#### 类型
560响应时延/完成时延
561#### 解决方法
562审视@Component标记的自定义组件,如果里面没有独立的生命周期处理逻辑,数据由父组件传递,建议@Builder替代。
563#### 反例
564```typescript
565@Entry
566@Component
567struct CEMineButtomView {
568  build() {
569    View();
570  }
571}
572
573@Component
574export struct ViewA {
575  build() {
576    Row() {
577      Text('- 到底了 -')
578        .fontSize(12)
579        .fontColor($r("app.color.color_1"))
580    }.justifyContent(FlexAlign.Center)
581     .width('100%')
582     .height(51)
583     .padding({ bottom: 21 })
584  }
585}
586```
587#### 正例
588```typescript
589@Builder
590function viewB() {
591  Row() {
592    Text('- 到底了 -').fontSize(12)
593      .fontColor($r("app.color.color_1"))
594  }
595  .justifyContent(FlexAlign.Center)
596    .width('100%')
597    .height(51)
598    .padding({ bottom: 21 })
599}
600
601@Entry
602@Component
603struct CEMineButtomView {
604  build() {
605    Column(){
606      viewB()
607    }.width('100%')
608  }
609}
610```
611#### 高频程度&收益(5满分)
6123
613
614### 删除无具体逻辑的生命周期,ArkUI的函数回调等,删除冗余堵塞日志打印
615#### 类型
616响应时延/完成时延/帧率
617#### 解决方法
618排查所有的aboutToAppear、aboutToDisappear等生命周期函数,排查ArkUI的回调函数,如果函数中无具体业务逻辑,
619例如只打印了日志,删除函数回调。
620#### 反例
621```typescript
622import promptAction from '@ohos.promptAction';
623
624@Entry
625@Component
626struct ViewA {
627  aboutToAppear(): void {
628    hilog.info('Index.ets aboutToAppear')  // 无具体业务逻辑的日志
629  }
630
631  aboutToDisappear(): void{
632    hilog.info('Index.ets aboutToDisappear') // 无具体业务逻辑的日志
633  }
634
635  /**
636   * 弹窗函数
637   */
638  showToast() {
639    promptAction.showToast({
640      message: $r('app.string.water_mark_toast_message')
641    })
642  }
643
644  build() {
645    Column(){
646      Text('测试一下')
647        .onClick(() => {
648          this.showToast(); // 有业务逻辑的方法
649        })
650    }.width('100%')
651  }
652}
653```
654#### 正例
655```typescript
656import promptAction from '@ohos.promptAction';
657
658@Entry
659@Component
660struct ViewB {
661  /**
662   * 弹窗函数
663   */
664  showToast() {
665    promptAction.showToast({
666      message: $r('app.string.water_mark_toast_message')
667    })
668  }
669
670  build() {
671    Column(){
672      Text('测试一下')
673        .onClick(() => {
674          this.showToast(); // 有业务逻辑的方法
675        })
676    }.width('100%')
677  }
678}
679```
680#### 高频程度&收益(5满分)
6813
682
683### 删除未关联组件的状态变量装饰器
684#### 类型
685响应时延/完成时延
686#### 解决方法
687排查全局的状态变量装饰器,如果变量未关联组件,删除装饰器。
688#### 反例
689```typescript
690@Component
691struct ComponentA {
692  @State message: string = 'Hello World';
693  @State textColor: string | Color = '#007DFF';
694  @State bgcolor: string | Color = '#ffffff'; // 变量bgcolor是没有关联组件的
695  @State selectColor: string | Color = '#007DFF'; // 变量selectColor是没有关联组件的
696
697  build() {
698    Column(){
699      Text(this.message)
700        .fontSize(50)
701        .fontWeight(FontWeight.Bold)
702        .fontColor(this.textColor)
703    }
704  }
705}
706```
707#### 正例
708```typescript
709@Component
710struct ComponentB {
711  @State message: string = 'Hello World';
712  @State textColor: string | Color = '#007DFF';
713  bgcolor: string | Color = '#ffffff'; // 变量bgcolor是有关联组件的
714  selectColor: string | Color = '#007DFF'; // 变量selectColor是有关联组件的
715
716  build() {
717    Column(){
718      Text(this.message)
719        .fontSize(50)
720        .fontWeight(FontWeight.Bold)
721        .fontColor(this.selectColor)
722        .backgroundColor(this.bgcolor)
723    }
724  }
725}
726```
727#### 高频程度&收益(5满分)
7282
729
730### crypto-js性能差
731#### 类型
732帧率
733#### 解决方法
734排查buffer.from关键字,加密建议使用原生的cryptoFramework,然后将buffer替换为base64helper,性能提升10倍以上,
735且数据量越大越明显。
736#### 反例
737```typescript
738new Uint8Array(buffer.from(str,'base64').buffer);
739```
740#### 正例
741```typescript
742let that = new util.Base64Helper();
743let result = that.decodeSync(str);
744```
745#### 高频程度&收益(5满分)
7462
747
748### 不建议使用Marquee组件
749#### 类型
750响应时延/完成时延
751#### 解决方法
752排查Marquee关键字,使用Text的跑马灯模式(TextOverflow.MARQUEE)替代。
753#### 反例
754```typescript
755struct ViewA {
756  build() {
757    Column() {
758      Marquee({
759        start: this.start,
760        step: this.step,
761        loop: this.loop,
762        fromStart: this.fromStart,
763        src: this.src
764      })
765        .width(360)
766        .height(80)
767        .fontColor('#FFFFFF')
768        .fontSize(48)
769        .fontWeight(700)
770        .backgroundColor('#182431')
771        .margin({ bottom: 40 })
772        .onStart(() => {
773          console.info('Marquee animation complete onStart')
774        })
775        .onBounce(() => {
776          console.info('Marquee animation complete onBounce')
777        })
778        .onFinish(() => {
779          console.info('Marquee animation complete onFinish')
780        })
781    }.width("100%")
782  }
783}
784```
785#### 正例
786```typescript
787struct ViewB {
788  build(){
789    Column(){
790      Text(reply.user)
791        .maxLines(1)
792        .textOverflow({ overflow: TextOverflow.MARQUEE }) // 跑马灯模式
793        .width("30%")
794    }.width("100%")
795  }
796}
797```
798#### 高频程度&收益(5满分)
7991
800
801### 不能使用函数作为ArkUI组件的属性和组件复用的自定义组件的入参
802#### 类型
803完成时延
804#### 解决方法
805查看属性是否有xx()函数写法,确认函数/方法中是否有耗时操作,替换成变量。
806#### 反例
807```typescript
808struct ViewA {
809  build() {
810    Column() {
811      List() {
812        LazyForEach(this.data, (item: string) => {
813          ListItem() {
814            // 此处sum参数是函数获取的,每次组件复用都会重复触发此函数的调用
815            ChildComponent({ desc: item, sum: this.count() })
816          }.width('100%').height(100)
817        }, (item: string) => item)
818      }
819    }
820  }
821}
822```
823#### 正例
824```typescript
825struct ViewB {
826  @State sum: number = 0;
827
828  aboutToAppear(): void {
829    this.sum = this.count();
830  }
831
832  build() {
833    Column() {
834      List() {
835        LazyForEach(this.data, (item: string) => {
836          ListItem() {
837            ChildComponent({ desc: item, sum: this.sum })
838          }.width('100%').height(100)
839        }, (item: string) => item)
840      }
841    }
842  }
843}
844
845```
846#### 高频程度&收益(5满分)
8471
848
849### 不建议使用.linearGradient颜色渐变属性
850#### 类型
851完成时延
852#### 解决方法
853排查linearGradient关键字,可以使用图片代替。
854#### 反例
855```typescript
856Row()
857  .linearGradient({
858    angle: 90,
859    colors: [[0xff0000, 0.0], [0x0000ff, 0.3], [0xffff00, 1.0]]
860  })
861```
862#### 正例
863```typescript
864Image($r('app.media.gradient_color'))
865```
866#### 高频程度&收益(5满分)
8671
868
869### 不要在for/while循环中执行耗时操作
870#### 类型
871完成时延/帧率
872#### 解决方法
873排查for/while循环,查看里面是否有打印日志或者Trace。
874#### 反例
875```typescript
876@Component
877struct ViewA {
878  @State message: string = "";
879
880  build() {
881    Column() {
882      Button('点击打印日志').onClick(() => {
883        for (let i = 0; i < 10; i++) {
884          console.info(this.message);
885        }
886      })
887    }
888  }
889}
890```
891#### 正例
892```typescript
893@Component
894struct ViewB {
895  @State message: string = "";
896
897  build() {
898    Column() {
899      Button('点击打印日志').onClick(() => {
900        let logMessage: string = this.message;
901        for (let i = 0; i < 10; i++) {
902          console.info(logMessage); // 状态变量需先赋值,再调用会优化性能
903        }
904      })
905    }
906  }
907}
908```
909#### 高频程度&收益(5满分)
9101
911
912### 变量初值不建议设置为undefined,需进行默认初始化
913#### 类型
914完成时延
915#### 解决方法
916例如number设置为0,string设置为空字符串等,这样在使用过程中更不需要增加额外判空。
917排查类中的变量,看看是否有初始化为undefined。
918#### 反例
919```typescript
920@State channels?: Channels[] = undefined;
921```
922#### 正例
923```typescript
924@State channels?: Channels[] = [];
925```
926#### 高频程度&收益(5满分)
9271
928
929<!--no_check-->
930
931
932