-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathNG0201.tw.vtt
216 lines (150 loc) · 6.77 KB
/
NG0201.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
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
WEBVTT
Kind: subtitles
Language: zh-TW
00:00.720 --> 00:04.480
NullInjectorError: No provider\h
for the injectable class.\h
00:04.480 --> 00:07.360
当你尝试注入一个服务,却没有声明对应的提供者时
就会遇到本错误
00:07.360 --> 00:12.000
换句话说,你的代码尝试使用某个依赖
00:12.000 --> 00:17.120
但是 Angular 却无法找到或注入那个依赖
00:17.120 --> 00:21.520
因为目前没有任何提供者指向它
但所谓的“提供者”到底是什么呢?
00:21.520 --> 00:26.400
你可以把它看一个药物的处方,这个“处方”就是提供者
00:26.400 --> 00:31.200
而这个药物就是用于注入的服务。本错误告诉我们的是
00:31.200 --> 00:36.720
我们正试图使用一种没有处方的药物
可以用两种方式解决此问题:
00:36.720 --> 00:42.320
@Injectable 装饰器,或者在 ngModule 的 providers 数组中
无论哪种方式,提供者都由三部分主要信息构成
00:42.320 --> 00:46.560
首先,它需要知道在哪里让这个类可用
00:46.560 --> 00:50.480
比如应用的根模块或特性模块
00:50.480 --> 00:55.840
其次,它需要一个令牌(Token),以便在依赖注入体系中定位那个类
00:55.840 --> 01:01.280
这里的令牌是一个带有装饰器的类的类型
在多数情况下,此令牌和你要提供的类是同一个
01:01.280 --> 01:06.080
不过,你还可以提供第三部分信息,比如
01:06.080 --> 01:12.160
用 useClass 来提供完全不同的一个类,或者用 useValue 来提供一个原始值
01:12.160 --> 01:16.080
让我们看一组常见的范例及其快速修复方式
01:16.080 --> 01:20.000
然后我们会深入看一下注入器和提供者,以便在更基础的层面上
01:20.000 --> 01:24.880
理解为什么会发生此错误
在我们的代码中,有一个带有 @Injectable 装饰器的服务
01:24.880 --> 01:30.240
但目前,该服务还没有在应用内的任何 ngModule 中提供
01:30.240 --> 01:34.480
当我们试图在 AppComponent 的构造函数中中注入它时
01:34.480 --> 01:39.840
就会导致 NullInjectorError。此错误信息指出了出错的类
01:39.840 --> 01:44.160
现在,我们有两种主要的方式解决此问题
如果我们要在整个应用范围内提供这个类
01:44.160 --> 01:49.760
可以使用 providedIn: 'root' 选项。它会提供一个全局单例
01:49.760 --> 01:54.320
此单例可以用于应用中的任何地方,并消除本错误
01:54.320 --> 01:59.520
不过,这可能并不总是最合适的解决方案
某些情况下,更有效的方式是把某个服务局限在某个特性模块内部
01:59.520 --> 02:04.880
这可以通过把某个 ngModule 类作为 providedIn 选项的值来实现
02:04.880 --> 02:09.760
这样就让我们可以从应用的主 JS 包中排除这部分代码,按需惰性加载
02:09.760 --> 02:14.800
这可以提升加载性能。当你有一个要在独立模块中书踹死的服务时,这很好
02:14.800 --> 02:20.160
但是如果该服务被多个惰性加载模块使用时怎么办呢?
02:20.160 --> 02:25.600
这种情况下,你可能希望每个模块都为本服务创建它自己的实例
02:25.600 --> 02:30.240
这可以通过 providedIn: 'any' 选项来实现
02:30.240 --> 02:35.600
这种方式下,服务不是单例的,而是为每个模块创建一个实例
02:35.600 --> 02:40.560
还有一个选项是 providedIn: 'platform'
02:40.560 --> 02:46.160
它适用于那些要在同一个页面中使用多个 Angular 应用的项目
比如通过 Angular Elements 实现的 Web Components
02:46.160 --> 02:50.640
在同一个页面中的所有 Angular 应用中可用
02:51.200 --> 02:54.240
总之,一共有四种不同的方式来提供某个服务
02:54.240 --> 02:57.440
'root' 会为整个 Angular 应用实例化一个单例
02:57.440 --> 03:00.880
“模块类”会单独为那个模块提供一个单例
03:00.880 --> 03:04.000
'any' 会为每个注入它的模块提供一个实例
03:04.000 --> 03:07.760
而 'platform' 会为多个 Angular 应用提供一个单例
03:08.320 --> 03:13.600
另外,你还可以在 ngModule 装饰器中直接提供某个服务
03:13.600 --> 03:18.000
只要导入你要提供的服务
然后把它加到 ngModule 装饰器的 providers 数组中就可以了
03:18.000 --> 03:22.880
这种模式也会创建一个提供者,不过通常不建议使用这种方式
03:22.880 --> 03:27.520
因为它会让这些代码在没有任何地方注入它的时候,难以摇树优化掉
03:27.520 --> 03:32.960
很多情况下,你可能遇到来自第三方依赖或
03:32.960 --> 03:38.640
比如,如果在 AppComponent 中导入 HTTP Client,然后
03:38.640 --> 03:43.680
把它注入为构造函数中的一个依赖项,同样会抛出一个错误
03:43.680 --> 03:48.080
但是你可能想不通为什么 Angular 内置的东西还会没有提供者
03:48.080 --> 03:53.280
这是因为只有极少数服务才内置到了 Angular 内核中
其它的一切几乎都拆到了自己的模块中
03:53.280 --> 03:59.200
这意味着要使用 HTTP Client,我们就要
03:59.200 --> 04:04.560
在依赖它的模块(AppModule)中导入其对应的 ngModule
04:04.560 --> 04:09.520
我们可以通过把它加入到 AppModule 的 imports 数组中来实现
现在,我们知道了如何修复此错误,接下来我们谈谈注入器
04:09.520 --> 04:14.960
当 Angular 启动时,它会创建一个全应用级注入器
04:14.960 --> 04:20.320
它的职责是创建和管理依赖,它会维护一个提供者的集合
04:20.320 --> 04:26.320
每个提供者具有一个令牌或类的类型
它会告诉 Angular 去哪里寻找要注入的值
04:26.320 --> 04:30.720
大多数情况下,提供者是通过 @Injectable 装饰器来创建的
04:30.720 --> 04:35.120
比如当某个组件的构造函数中引用了这个类的时候
04:35.120 --> 04:40.400
注入器就会使用此提供者来寻找该类的现有实例,或者按需实例化一个新的
04:40.400 --> 04:44.640
每个依赖项都需要至少一个提供者,否则就会抛出 NullInjectorError
04:44.640 --> 04:49.520
如果没有提供者,它就不能正常工作。我们来回顾一下
04:49.520 --> 04:54.320
当你遇到 NullInjectorError 时
它表示某个要注入的服务没有必要的提供者
04:54.320 --> 04:59.680
第一步是找到那个导致错误的类。如果它是你自己的 @Injectable 类之一
04:59.680 --> 05:04.640
你可以在应用的根或者某个 ngModule 中提供它
05:04.640 --> 05:08.960
如果它和某个第三方依赖有关,可能是你忘了导入某个 ngModule
05:08.960 --> 05:14.080
你要找出那个服务是在哪里提供的,然后导入对应的 ngModule
05:14.080 --> 05:19.920
欲知详情和范例,请阅读Angular官方文档的“依赖注入”指南