-
Notifications
You must be signed in to change notification settings - Fork 1
/
CpLOm4o_FzM.tw.vtt
117 lines (82 loc) · 3.76 KB
/
CpLOm4o_FzM.tw.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
WEBVTT
Kind: subtitles
Language: zh-TW
00:00.240 --> 00:04.080
Circular dependency in DI detected.
当你遇到某个依赖其自身的依赖项时,就会出现本错误
00:04.080 --> 00:09.200
有时是直接依赖,但更常见的是间接依赖
00:09.200 --> 00:13.600
浏览器的控制台中会抛出一个运行时错误,告诉你哪个类受到了影响
00:13.600 --> 00:18.400
更有用的是,此警告会同时显示在浏览器控制台和命令行终端里
00:18.400 --> 00:21.760
最重要的是,它提供了此循环依赖的依赖路径
00:21.760 --> 00:26.960
仔细去看,它还会告诉我们,我们的一个 Storage 类注入了某个 User 类
00:26.960 --> 00:31.520
而这个 User 类本身又依赖原来那个 Storage 类
我们继续前进,来看一个简单的重现过程
00:31.520 --> 00:35.680
然后我们会花一些时间,来深入理解 Angular 的依赖注入体系
00:35.680 --> 00:40.480
仔细看源码,你会注意到我们有两个服务,User 和 Storage
00:40.480 --> 00:45.600
问题在于 User 类在自己的构造函数中注入了一个 Storage 类
00:45.600 --> 00:49.840
而 Storage 类也在自己的构造函数中注入了一个 User 类
这导致它们陷入了一种不正常的“相互依赖”关系中
00:49.840 --> 00:54.800
此问题的解决方案是要打破这种依赖,因此要做某种重构
00:54.800 --> 00:59.440
让某个 @Injectable 依赖另一个 @Injectable 固然是没问题的
00:59.440 --> 01:04.640
但这种依赖关系只应该是单向的,这意味着我们需要重构
01:04.640 --> 01:10.400
以便从 Storage 中移除 User 服务
或者反过来,从 User 中移除 Storage 服务
01:10.400 --> 01:14.800
一般而言,最好将 @Injectable 服务中依赖项的数量最小化
01:14.800 --> 01:20.000
因为那样也会减少将来出现类似问题的可能性
目前,我们的 Storage 类中有一个方法
01:20.000 --> 01:25.040
用来把此用户写入数据库中,但是它依赖 User 服务,以获取当前用户的值
01:25.040 --> 01:30.480
我们可以通过重构代码来解决此问题:
改用参数接收此用户的值,而不再注入完整的用户类
01:30.480 --> 01:35.120
这不仅能让我们从构造函数中移除此依赖项
01:35.120 --> 01:39.040
还能让代码更便于进行单元测试,因为你不再
01:39.040 --> 01:44.320
需要 Mock 或关心一个额外的依赖项,该方法将只依赖其输入参数
01:44.320 --> 01:49.600
这会让测试更简单。现在,我们保存这些修改,此错误消失了
01:49.600 --> 01:54.480
但是在结束讨论之前,我们先对 Angular 的依赖注入体系做一个深入研究
01:54.480 --> 01:59.280
以便理解为什么会出现本错误
当你使用 Angular CLI 生成某个服务时,你会注意到
01:59.280 --> 02:04.000
该类带有 @Injectable 装饰器
当它带有 \{ providedIn: 'root' \} 选项时
02:04.000 --> 02:07.840
Angular 就会实例化此类,并且让他在整个应用中可见
02:08.400 --> 02:13.040
和组件不同,该类只会作为单例对象实例化一次
02:13.040 --> 02:17.760
那么,如果有两个类互相依赖,你要如何决定先实例化哪个呢?
02:17.760 --> 02:21.760
这是一个经典的先有鸡还是先有蛋的悖论
并且,如果你要遵循依赖倒置原则,它也是不合理的
02:21.760 --> 02:26.960
让我们简要回顾一下。当你遇到了 DI 检测到循环依赖的情况时
02:26.960 --> 02:31.600
第一步是通过组件和服务的构造函数来找出
02:31.600 --> 02:35.680
到底是哪些依赖项产生了循环依赖
02:35.680 --> 02:40.160
找出来之后,你可以重构代码以打破这种循环
02:40.160 --> 02:44.720
欲知详情和范例,请阅读Angular官方文档的“依赖注入”指南