-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
88 changed files
with
28,674 additions
and
13 deletions.
There are no files selected for viewing
852 changes: 852 additions & 0 deletions
852
assets/videos/4 Runtime Performance Optimizations-f8sA-i6gkGQ.cn.vtt
Large diffs are not rendered by default.
Oops, something went wrong.
1,350 changes: 1,350 additions & 0 deletions
1,350
assets/videos/4 Runtime Performance Optimizations-f8sA-i6gkGQ.en.vtt
Large diffs are not rendered by default.
Oops, something went wrong.
852 changes: 852 additions & 0 deletions
852
assets/videos/4 Runtime Performance Optimizations-f8sA-i6gkGQ.tw.vtt
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
WEBVTT | ||
Kind: subtitles | ||
Language: zh-CN | ||
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官方文档的“依赖注入”指南 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
WEBVTT | ||
Kind: subtitles | ||
Language: en | ||
00:00.240 --> 00:04.080 | ||
Circular dependency in DI detected. | ||
You'll encounter this error when you\h\h | ||
|
||
00:04.080 --> 00:09.200 | ||
have a dependency that depends on itself,\h | ||
either directly, or more often indirectly.\h | ||
|
||
00:09.200 --> 00:13.600 | ||
A runtime error will be thrown in the browser\h | ||
console telling you which class is effected, but\h\h | ||
|
||
00:13.600 --> 00:18.400 | ||
what's perhaps more useful is a warning that can\h | ||
be seen both in the console and in the terminal.\h | ||
|
||
00:18.400 --> 00:21.760 | ||
Most importantly, it provides the\h | ||
path of the circular dependency.\h | ||
|
||
00:21.760 --> 00:26.960 | ||
If we look closely, it's telling us we have a\h | ||
storage class that injects a user class, which\h\h | ||
|
||
00:26.960 --> 00:31.520 | ||
itself depends on the original storage class. | ||
Let's go ahead and look at a simple reproduction,\h\h | ||
|
||
00:31.520 --> 00:35.680 | ||
and then we'll take some time to go in depth\h | ||
about angular's dependency injection system.\h | ||
|
||
00:35.680 --> 00:40.480 | ||
If we take a look at our source code, you'll\h | ||
notice we have two services, user and storage.\h | ||
|
||
00:40.480 --> 00:45.600 | ||
The problem is that user has injected storage\h | ||
in its constructor and storage has injected\h\h | ||
|
||
00:45.600 --> 00:49.840 | ||
user in its constructor, putting them in\h | ||
an impossible codependent relationship.\h | ||
|
||
00:49.840 --> 00:54.800 | ||
The solution to this problem is to break the loop,\h | ||
which will most likely require some refactoring.\h\h | ||
|
||
00:54.800 --> 00:59.440 | ||
It's perfectly okay for an @Injectable to depend\h | ||
on another @Injectable, but the relationship\h\h | ||
|
||
00:59.440 --> 01:04.640 | ||
can only go one way, which means in this case we\h | ||
need to refactor to remove the user service from\h\h | ||
|
||
01:04.640 --> 01:10.400 | ||
storage, or vice versa, remove the storage service\h | ||
from user, and generally speaking, it's a good\h\h | ||
|
||
01:10.400 --> 01:14.800 | ||
idea to minimize the number of dependencies in\h | ||
an @Injectable service, because that will reduce\h\h | ||
|
||
01:14.800 --> 01:20.000 | ||
the likelihood of similar issues coming up in the\h | ||
future. Now in our storage class we have a method\h\h | ||
|
||
01:20.000 --> 01:25.040 | ||
to write the user to the database, but it depends\h | ||
on the user service for the current user value.\h\h | ||
|
||
01:25.040 --> 01:30.480 | ||
We can address the problem here by refactoring\h | ||
our code to take the user value as an argument,\h\h | ||
|
||
01:30.480 --> 01:35.120 | ||
rather than inject the entire user class. Not only\h | ||
does that allow us to remove the dependency from\h\h | ||
|
||
01:35.120 --> 01:39.040 | ||
the constructor, it will also make this code\h | ||
easier to unit test, because you don't have\h\h | ||
|
||
01:39.040 --> 01:44.320 | ||
an additional dependency to mock or worry about,\h | ||
and the method only depends on its input arguments\h\h | ||
|
||
01:44.320 --> 01:49.600 | ||
making it easier to reason about. Now if we go\h | ||
ahead and save our changes, the error is gone. But\h\h | ||
|
||
01:49.600 --> 01:54.480 | ||
before we wrap things up, let's take a deeper look\h | ||
at Angular's dependency injection to understand\h\h | ||
|
||
01:54.480 --> 01:59.280 | ||
why this error happens in the first place. When\h | ||
you generate a service with the Angular CLI you'll\h\h | ||
|
||
01:59.280 --> 02:04.000 | ||
notice how the class is decorated with @Injectable\h | ||
when used with the \{ providedIn: 'root' \} option,\h\h | ||
|
||
02:04.000 --> 02:07.840 | ||
Angular will instantiate the class and make\h | ||
it visible throughout the entire application.\h\h | ||
|
||
02:08.400 --> 02:13.040 | ||
Unlike a component, this class is only\h | ||
instantiated once as a singleton. Now\h\h | ||
|
||
02:13.040 --> 02:17.760 | ||
imagine two classes that depend on each other, how\h | ||
do you determine which one to instantiate first?\h\h | ||
|
||
02:17.760 --> 02:21.760 | ||
It's a classic chicken or the egg paradox, and\h | ||
that just doesn't work when you're following\h\h | ||
|
||
02:21.760 --> 02:26.960 | ||
the dependency inversion principle. Let's go ahead\h | ||
and recap. When you encounter circular dependency\h\h | ||
|
||
02:26.960 --> 02:31.600 | ||
in DI detected, the first step is to determine\h | ||
which dependencies create a loop by mapping\h\h | ||
|
||
02:31.600 --> 02:35.680 | ||
out the dependencies and the constructor\h | ||
of your components modules and services.\h\h | ||
|
||
02:35.680 --> 02:40.160 | ||
Once identified you can then refactor your code\h | ||
to break the loop. For additional details and\h\h | ||
|
||
02:40.160 --> 02:44.720 | ||
examples check out the dependency injection\h | ||
guide in the official Angular documentation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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官方文档的“依赖注入”指南 |
Oops, something went wrong.