-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathf8sA-i6gkGQ.cn.vtt
852 lines (597 loc) · 20.4 KB
/
f8sA-i6gkGQ.cn.vtt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
WEBVTT
Kind: subtitles
Language: zh-CN
00:00:00.000 --> 00:00:01.390
MINKO GECHEV: 大家好
00:00:01.390 --> 00:00:02.670
我是 Minko Gechev
00:00:02.670 --> 00:00:05.490
我在谷歌做 Angular 开发
00:00:05.490 --> 00:00:06.067
这几年
00:00:06.067 --> 00:00:08.705
我分析了数百个 Angular 应用程序
00:00:08.705 --> 00:00:15.034
而且我注意到大多数性能方面的挑战都有
几种典型的模式
00:00:14.902 --> 00:00:18.495
今天,我们将研究这些模式
00:00:18.495 --> 00:00:21.340
并学习如何解决它们
00:00:21.340 --> 00:00:22.343
在本视频中
00:00:22.343 --> 00:00:25.810
你将首先学习如何使用 Angular DevTools
00:00:25.810 --> 00:00:26.381
之后
00:00:26.381 --> 00:00:31.864
我们将识别几种导致性能退化的模式
并学习如何解决它们
00:00:31.750 --> 00:00:32.429
为此
00:00:32.429 --> 00:00:37.450
我们将使用一个典型业务应用的简单原型
00:00:37.450 --> 00:00:41.290
在 UI 的最顶部,我们有一个柱状图
00:00:41.290 --> 00:00:42.738
在这个图表下方
00:00:42.738 --> 00:00:48.531
我们有两份来自销售和研发部门的员工名单
00:00:48.400 --> 00:00:54.784
每个员工都有一个姓名和一个
经过繁重计算的与其关联的数值
00:00:54.670 --> 00:00:56.771
在这些列表中的任何一个
00:00:56.771 --> 00:00:58.690
我们都可以查询新员工
00:00:58.690 --> 00:01:01.142
正如你将在代码中所见到的那样
00:01:01.142 --> 00:01:03.230
还有用来实现主要功能的基础设施
00:01:03.230 --> 00:01:07.660
但为简单起见,它不是 UI 的一部分
00:01:07.660 --> 00:01:13.289
还记得我提到过每个员工的数值都要经过繁重
计算吗?
00:01:13.289 --> 00:01:14.880
为了简单起见
00:01:14.880 --> 00:01:18.673
我用斐波那契函数模拟了这个计算
00:01:18.550 --> 00:01:19.388
请注意
00:01:19.388 --> 00:01:24.413
我们已经实现了一个非常低效的斐波那契版本
00:01:24.413 --> 00:01:32.549
因此即使是很小的性能问题也会对我们将要
探索的示例产生显着的可见影响
00:01:32.310 --> 00:01:38.989
只用两个组件实现整个应用程序
EmployeeListComponent
00:01:38.989 --> 00:01:46.439
它包含相应部门的员工列表并有一个用于输
入新员工的文本输入框
00:01:46.439 --> 00:01:48.751
以及 AppComponent
00:01:48.751 --> 00:01:56.586
它会渲染 EmployeeListComponent 的
两个列表实例和顶部的柱状图
00:01:56.330 --> 00:01:58.515
在我们转到性能退化模式之前
00:01:58.515 --> 00:02:04.265
让我们看看如何使用 Angular DevTools
分析应用程序
00:02:04.150 --> 00:02:07.494
Angular DevTools 是一个
Chrome DevTools 扩展
00:02:07.494 --> 00:02:09.893
你可以从 Chrome 应用商店安装它
00:02:09.820 --> 00:02:14.359
它允许你在组件资源管理器中预览
应用程序的结构
00:02:14.260 --> 00:02:17.290
对于本视频,我们将主要使用 Profiler
00:02:17.290 --> 00:02:20.950
要开始分析应用程序,请单击“记录”按钮
00:02:20.950 --> 00:02:24.904
当 Angular 在你的应用程序中执行变更检
测时
00:02:24.904 --> 00:02:30.974
你会看到与 DevTools 时间轴中出现的各个
变更检测周期相对应的柱状图
00:02:30.790 --> 00:02:33.106
当我们从时间轴中选择帧时
00:02:33.106 --> 00:02:37.182
我们可以预览我们在各个组件上
花费了多少时间
00:02:37.090 --> 00:02:37.681
在这里
00:02:37.681 --> 00:02:44.014
我们在 MatFormField 和 EmployeeListComponent
中花费了大部分的变更检测调用
00:02:43.930 --> 00:02:51.752
DevTools 允许我们以不同的格式预览
Profiler 的输出:柱状图、树图和火焰图
00:02:51.640 --> 00:02:55.840
火焰图提供了组件树的分层视图
00:02:55.840 --> 00:02:57.699
当我们点击一个特定的组件时
00:02:57.699 --> 00:03:00.584
我们可以看到 Angular 在它上面花费了
多少时间
00:03:00.520 --> 00:03:01.168
例如
00:03:01.168 --> 00:03:08.949
我们花了大约 0.1 毫秒来检测 EmployeeListComponent
中的变化
00:03:08.820 --> 00:03:12.721
由于我们的应用程序没有复杂的嵌套结构
00:03:12.721 --> 00:03:15.990
因此我们将使用默认的柱状图视图
00:03:15.990 --> 00:03:18.360
现在让我们逐个看看这些模式
00:03:18.360 --> 00:03:21.420
我们将描述问题的原因
00:03:21.420 --> 00:03:26.370
你将学习如何识别它并解决它
00:03:26.370 --> 00:03:30.390
我们要研究的第一个模式是 Zone 污染
00:03:30.390 --> 00:03:36.429
让我们回到应用程序并开始使用 Angular DevTools
的 Profiler 进行记录
00:03:36.340 --> 00:03:40.245
如果我们开始与应用程序中的柱状图交互
00:03:40.245 --> 00:03:44.150
我们会看到我们触发了多个变更检测周期
00:03:44.150 --> 00:03:47.000
每个周期都需要相当长的时间
00:03:47.000 --> 00:03:50.115
如果我们探索变更检测周期
00:03:50.115 --> 00:03:56.844
我们将看到变更检测的来源是
mouseup 和 mousemove 事件
00:03:56.720 --> 00:04:00.370
每个循环需要超过 740 毫秒
00:04:00.370 --> 00:04:04.160
这会显著降低浏览器的帧率
00:04:04.160 --> 00:04:10.857
我们大部分时间都花在了 EmployeeListComponent
的两个实例上
00:04:10.857 --> 00:04:14.943
其中每次检查花费的时间超过了 360 毫秒
00:04:14.830 --> 00:04:17.320
现在让我们来解决这个问题
00:04:17.320 --> 00:04:22.416
app.component 模板的开头是我们渲染
柱状图的 div 容器
00:04:22.320 --> 00:04:32.632
我们通过调用 Plotly 图表库的新绘图方法
在 app.component 的 ngOnInit
生命周期挂钩上初始化 Ng 中的图表
00:04:32.430 --> 00:04:38.511
我们传递 DOM 容器的 ID 和我们要渲染的数据
00:04:38.370 --> 00:04:43.628
鉴于我们在 Profiler 中获得的
mouseup 和 mousemove 事件
00:04:43.628 --> 00:04:50.388
这意味着 Plotly 的初始化逻辑可能正在将
这些 EventListener 添加到柱状图
00:04:50.200 --> 00:04:52.475
Plotly 提供了一个独立的库
00:04:52.475 --> 00:04:54.400
不需要与 Angular 交互
00:04:54.400 --> 00:04:59.560
我们可以在 Angular Zone 之外运行
初始化逻辑
00:04:59.560 --> 00:05:03.040
以防止调用冗余的变更检测周期
00:05:02.920 --> 00:05:08.489
让我们转到 app.component 的构造函数并
注入 Ng Zone
00:05:08.380 --> 00:05:18.947
我们可以回到图表的初始化逻辑和我们传递
给 runOutsideAngular 的回调内部
00:05:18.810 --> 00:05:23.147
当我们返回应用程序并启动 Profiler 时
00:05:23.147 --> 00:05:29.007
我们会看到与柱状图中的条形的交互不再触
发变更检测
00:05:28.890 --> 00:05:33.762
当 Angular Zone 包装触发
冗余变更检测周期的回调时
00:05:33.762 --> 00:05:35.850
就会出现 Zone 污染模式
00:05:35.750 --> 00:05:43.678
当我们运行使用 requestAnimationFrame、setTimeout
或 addEventListener 的初始化逻辑时
00:05:43.678 --> 00:05:44.905
就会污染 Zone
00:05:44.810 --> 00:05:51.088
我们可以通过在 Profiler 输出中寻找意外
的变更检测周期来识别问题
00:05:50.990 --> 00:05:52.520
在大多数情况下
00:05:52.520 --> 00:05:56.090
我发现原因是 requestAnimationFrame
00:05:56.090 --> 00:05:58.050
解决方案通常非常简单
00:05:58.050 --> 00:06:02.980
你需要做的就是将初始化逻辑移出
Angular Zone
00:06:02.870 --> 00:06:07.855
我们将研究的以下模式是越界变更检测
00:06:07.855 --> 00:06:11.640
让我们回到应用程序并输入一个新员工
00:06:11.640 --> 00:06:14.210
请注意,可以体验到延迟很严重
00:06:14.210 --> 00:06:16.082
当我们开始分析时
00:06:16.082 --> 00:06:22.030
我们注意到我们输入的每个字符都会触发两
个变更检测周期
00:06:21.920 --> 00:06:25.052
第一个在 Input 事件上
00:06:25.052 --> 00:06:27.900
第二个在 keydown 上
00:06:27.900 --> 00:06:29.414
对于这两个事件
00:06:29.414 --> 00:06:36.481
我们花费了 380 多毫秒来检测 EmployeeListComponent
的两个实例中的变化
00:06:36.380 --> 00:06:37.364
请注意
00:06:37.364 --> 00:06:41.720
虽然我们只输入了销售部门的输入
00:06:41.720 --> 00:06:44.671
但我们也检查了研发部门
00:06:44.670 --> 00:06:50.644
由于键入这些输入只会更改销售部门内的视
图状态
00:06:50.644 --> 00:06:54.670
因此检测研发部门的变更是多余的
00:06:54.540 --> 00:06:56.130
让我们解决这个问题
00:06:56.130 --> 00:06:56.697
为此
00:06:56.697 --> 00:07:03.384
我们将 EmployeeListComponents 的
变更检测策略改为 OnPush
00:07:03.270 --> 00:07:04.591
使用 OnPush
00:07:04.591 --> 00:07:09.656
当我们基于 @Input 检查传入具有新值的
输入时
00:07:09.656 --> 00:07:13.070
Angular 将触发组件内的变更检测
00:07:12.960 --> 00:07:18.872
我们将使用 immutable.js 中的不可变列表
来防止数组引用发生变化
00:07:18.872 --> 00:07:21.256
并确保高效的数据共享结构
00:07:21.160 --> 00:07:26.511
让我们首先将销售和研发部门数组更改为不
可变列表
00:07:26.400 --> 00:07:27.021
之后
00:07:27.021 --> 00:07:33.732
我们将更新 app.component 中
Add 和 Remove 方法的签名
00:07:33.732 --> 00:07:37.833
以便它们可以接受不可变的员工列表
00:07:37.710 --> 00:07:38.393
接下来
00:07:38.393 --> 00:07:48.157
我们需要确保分配这两个方法产生的结果以
更新本地引用并将它们沿组件树向下传递给
EmployeeListComponent
00:07:48.060 --> 00:07:51.890
我们需要赋值,因为我们不能改变列表
00:07:51.890 --> 00:07:56.590
相反,Immutabe.js 会创建新的
00:07:56.590 --> 00:08:01.668
由于我们现在将不可变列表传递给 EmployeeListComponent
00:08:01.668 --> 00:08:04.830
因此我们需要更新其数据输入的类型
00:08:04.830 --> 00:08:08.238
不可变列表具有大小而不是长度属性
00:08:08.238 --> 00:08:15.673
因此我们需要更新模板中的属性访问并将 changeDetection
策略设置为 OnPush
00:08:15.570 --> 00:08:18.192
现在,让我们回到应用程序
00:08:18.192 --> 00:08:22.890
请注意,现在输入新员工的速度快了一点点
00:08:22.890 --> 00:08:25.630
虽然它仍然很慢
00:08:25.630 --> 00:08:26.860
让我们解决这个问题
00:08:26.860 --> 00:08:31.562
我们将它做作为越界变更检测重构的一部分
00:08:31.450 --> 00:08:33.455
当我们开始输入时
00:08:33.455 --> 00:08:36.640
Angular 会定期执行变更检测
00:08:36.640 --> 00:08:46.096
它检查整个 EmployeeListComponent 并对每个员工
运行两次繁重计算 —— 在 input 和 keypress 事件时
00:08:46.096 --> 00:08:48.685
哪怕没有任何值发生变化
00:08:48.460 --> 00:08:54.930
发生这种情况是因为在输入中键入会触发
绕过 OnPush 变更检测策略的事件
00:08:54.835 --> 00:08:59.771
当具有 OnPush 变更检测策略的组件内的
事件发生时
00:08:59.771 --> 00:09:02.548
Angular 将检测该组件的变化
00:09:02.548 --> 00:09:04.913
即使它没有收到新的输入
00:09:04.810 --> 00:09:09.731
这里的问题是我们只是在更改输入的本地状态
00:09:09.731 --> 00:09:12.129
而不是更新单个员工
00:09:12.129 --> 00:09:17.050
这意味着完全跳过他们的更改方向是安全的
00:09:17.050 --> 00:09:20.860
为了提高性能,我们将重构组件树
00:09:20.860 --> 00:09:21.419
目前
00:09:21.419 --> 00:09:26.672
app 组件渲染了 EmployeeListComponent 的
两个实例
00:09:26.560 --> 00:09:27.944
在本节的最后
00:09:27.944 --> 00:09:35.077
EmployeeListComponent 将使用 NameInputComponent
获取新员工的姓名
00:09:35.077 --> 00:09:38.697
并使用 ListComponent 渲染员工列表
00:09:38.590 --> 00:09:42.442
我们将为列表组件使用 OnPush 变更检测策略
00:09:42.350 --> 00:09:44.528
因此,通过这种方式
00:09:44.528 --> 00:09:53.241
兄弟组件 NameInputComponent 中发生的
事件将不会触发对员工的任何冗余计算
00:09:53.120 --> 00:10:01.887
让我们首先进入 EmployeeListComponent
的目录并创建 name-input.component 和 list.component
00:10:01.790 --> 00:10:02.814
下一步
00:10:02.814 --> 00:10:10.543
我们可以将输入字段从 employee-list.component
提取到 name-input.component 的模板中
00:10:10.450 --> 00:10:18.536
我们还可以移动相应的样式、label 属性和 handleKey
方法并复制输出
00:10:18.410 --> 00:10:21.145
我们还要删除 OnInit 生命周期钩子
00:10:21.145 --> 00:10:38.999
我们可以在 employee-list.component 的
模板中使用 name-input.component
00:10:38.999 --> 00:10:45.375
下一步处理应用程序的输出属性
00:10:45.120 --> 00:10:55.658
现在让我们将模板的其余 mat-list 部分
移至 ListComponent
00:10:55.470 --> 00:11:02.526
我们还应该拿出计算方法并删除 OnInit
生命周期挂钩实现
00:11:02.526 --> 00:11:05.270
因为我们根本不使用它
00:11:05.140 --> 00:11:10.565
接下来,让我们移动斐波那契函数
00:11:10.565 --> 00:11:18.480
我们现在可以移动数据输入了
00:11:18.480 --> 00:11:20.970
最后,我们可以复制删除输出
00:11:20.970 --> 00:11:29.883
为了确保 UI 看起来清晰
00:11:29.883 --> 00:11:50.808
我们可以将与列表可视化关联的样式移动到
列表组件的样式
00:11:50.420 --> 00:11:51.828
最后
00:11:51.828 --> 00:12:07.592
我们可以将 list.components 的变更检测
策略设置为 OnPush
00:12:07.310 --> 00:12:12.481
让我们使用 employee-list.components
模板中的 list.component
00:12:12.481 --> 00:12:14.939
传递相应的输入并删除输出属性
00:12:14.855 --> 00:12:20.071
当你返回应用程序时
00:12:20.071 --> 00:12:29.130
请注意打字体验已经没有任何明显的延迟了
00:12:29.130 --> 00:12:30.230
回顾一下
00:12:30.230 --> 00:12:38.299
当仅影响特定组件的本地状态的操作触发组
件的不相关部分的变更检测时
00:12:38.299 --> 00:12:40.622
就会出现这类性能问题
00:12:40.500 --> 00:12:50.475
我们可以通过检查 Profiler 的输出并找到
不应受特定交互影响的组件来识别问题
00:12:50.340 --> 00:12:52.252
为了解决这个问题
00:12:52.252 --> 00:12:56.638
我们可以隔离触发频繁本地状态更改的组件
00:12:56.638 --> 00:13:02.373
并将具有昂贵的变更检测检查的组件设置为
使用 OnPush 的
00:13:02.260 --> 00:13:10.042
我们要看的第三种模式是引用透明表达式的
重新计算
00:13:09.880 --> 00:13:13.280
如果我们在模板中有一个表达式
00:13:13.280 --> 00:13:17.149
当它的参数不变时就可以用它的值替代它
00:13:17.149 --> 00:13:19.611
我们就认为它是引用透明的
00:13:19.610 --> 00:13:24.957
这意味着我们不必在变更检测周期之间
重新计算表达式
00:13:24.957 --> 00:13:27.417
除非它们的输入发生变化
00:13:27.310 --> 00:13:30.370
让我们回到应用程序并添加一名员工
00:13:30.370 --> 00:13:31.000
请注意
00:13:31.000 --> 00:13:35.950
我们得到了一个由 keydown 事件触发的
相当昂贵的变更检测周期
00:13:35.860 --> 00:13:38.656
我们降低了浏览器的帧率
00:13:38.656 --> 00:13:44.491
Angular 将大部分变更检测周期都花在了
列表组件中
00:13:44.370 --> 00:13:47.833
当我们将新员工添加到 Sales 列表时
00:13:47.833 --> 00:13:50.787
我们调用了 app 组件的 add 方法
00:13:50.787 --> 00:13:53.130
这会创建一个不可变列表
00:13:53.130 --> 00:13:58.755
不可变列表将新的不可变列表传递给 ListComponent
00:13:58.755 --> 00:14:00.550
触发其变更检测
00:14:00.550 --> 00:14:06.409
Angular 遍历各个员工并重新计算他们的
数值
00:14:06.409 --> 00:14:08.673
即使他们没有改变
00:14:08.540 --> 00:14:14.310
理想情况下,你只想计算新员工的价值
00:14:14.310 --> 00:14:19.411
我们可以通过一点重构来提高应用程序的性能
00:14:19.290 --> 00:14:22.498
我们可以创建一个名为 calculate 的新管道
00:14:22.420 --> 00:14:27.798
让我们导入管道装饰器并将管道名称设置为
“calculate”
00:14:27.798 --> 00:14:28.616
在这里
00:14:28.616 --> 00:14:32.241
我们明确写出此管道对于读来说是“纯的”
00:14:32.241 --> 00:14:34.696
虽然这是属性的默认值
00:14:34.580 --> 00:14:35.268
下一步
00:14:35.268 --> 00:14:38.219
我们可以实现 CalculatePipe 类
00:14:38.219 --> 00:14:42.448
添加一个转换方法并实现 PipeTransform
接口
00:14:42.350 --> 00:14:55.021
现在让我们移动 Fibonacci 实现并从 ListComponent
中删除冗余的计算方法
00:14:54.840 --> 00:15:07.801
让我们将 CalculatePipe 添加到 employee-list.module
中的声明中
00:15:07.595 --> 00:15:08.998
最后
00:15:08.998 --> 00:15:25.551
我们需要更新 ListComponent 的模板以使
用管道而不是方法调用
00:15:25.270 --> 00:15:25.737
请注意
00:15:25.737 --> 00:15:28.937
现在我们可以在没有任何明显延迟的情况下
添加员工
00:15:28.870 --> 00:15:30.435
回顾一下
00:15:30.435 --> 00:15:38.261
当 Angular 重复地重新计算相同的
模板表达式时
00:15:38.261 --> 00:15:43.305
即使它们仅依赖于值不变的参数
00:15:43.305 --> 00:15:45.914
也会出现此问题
00:15:45.740 --> 00:15:55.707
我们可以通过注意到变更检测周期与我们在 UI
中所做的更改不成比例的时间来识别
Angular DevTools 的问题
00:15:55.510 --> 00:16:03.759
解决方案通常涉及将计算移动到纯管道或通过记忆缓存它
00:16:03.600 --> 00:16:08.700
我们要看的最后一个模式是大型组件树
00:16:08.700 --> 00:16:13.352
即使我们优化了每个组件并且不执行冗余计算
00:16:13.352 --> 00:16:16.121
如果我们有数千个组件实例
00:16:16.121 --> 00:16:18.890
我们仍然可以观察到丢帧
00:16:18.780 --> 00:16:22.159
为了展示我们如何在这种情况下提高性能
00:16:22.159 --> 00:16:24.990
我在每个列表中添加了几百名员工
00:16:24.990 --> 00:16:27.538
当我们添加一名新员工时
00:16:27.538 --> 00:16:33.410
我们注意到检测 ListComponent 的变化需
要超过 25 毫秒
00:16:33.410 --> 00:16:34.850
这会导致丢帧
00:16:34.740 --> 00:16:40.350
提高大型组件树的性能的关键是让组件树更小
00:16:40.350 --> 00:16:46.020
标准技术是按需渲染,例如虚拟化或分页
00:16:46.020 --> 00:16:47.752
出于我们的目的
00:16:47.752 --> 00:16:52.140
我们将使用 Angular CDK 的虚拟滚动组件
00:16:52.140 --> 00:16:54.800
在 ListComponent 的模板中
00:16:54.800 --> 00:17:00.630
我们将使用项目大小等于 50 的 cdk_virtual_scroll_viewport
00:17:00.630 --> 00:17:03.537
我们还将添加 CSS 类“Viewport”
00:17:03.537 --> 00:17:06.780
以便我们可以设置此组件的样式
00:17:06.780 --> 00:17:09.288
我们将使用 cdkVirtualFor
00:17:09.288 --> 00:17:12.599
而不是在 mat-list 项中使用 ngFor
00:17:12.599 --> 00:17:18.079
我们还将容器的高度设置为 800 像素
00:17:18.079 --> 00:17:21.240
就这样
00:17:21.240 --> 00:17:23.755
现在,当我们添加一个新项目时
00:17:23.755 --> 00:17:28.245
ListComponent 中的更改部分花费的时间是
以前的 1/5
00:17:28.155 --> 00:17:29.265
请记住
00:17:29.265 --> 00:17:36.242
即使你拥有高度优化的组件并渲染了数千个组件
00:17:36.242 --> 00:17:43.537
它们的模板组合在变更检测期间仍然可能非常昂贵
00:17:43.220 --> 00:17:48.445
如果你发现许多组件只占用
整个变更检测周期的一小部分
00:17:48.445 --> 00:17:54.273
或者当有一个组件具有非常大的视图需要
花费大量时间来检查时
00:17:54.273 --> 00:17:57.790
你可以在 DevTools 中识别此问题
00:17:57.590 --> 00:18:03.152
该解决方案涉及组件的按需渲染以修剪组件树
00:18:03.020 --> 00:18:05.300
这就是我今天要给你讲的全部内容
00:18:05.300 --> 00:18:09.968
我们首先了解了使用 Angular DevTools 的
基础知识
00:18:09.968 --> 00:18:11.427
重点关注分析器
00:18:11.330 --> 00:18:12.006
之后
00:18:12.006 --> 00:18:27.681
我们探索了四种可以帮助你识别和解决常见
性能问题的模式 —— Zone 污染、越界、
变更检测、引用透明表达式的重新计算和大型组件树
00:18:27.410 --> 00:18:29.460
非常感谢你观看此视频
00:18:29.460 --> 00:18:32.350
回见,祝编码愉快