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