patch up guide\dependency-injection.jade after official updates.
This commit is contained in:
parent
633964ac2f
commit
cb8818f171
|
@ -19,12 +19,18 @@ block includes
|
|||
然后,我们将学习在Angular应用中该[如何使用它](#angular-di)。
|
||||
|
||||
- [Why dependency injection?](#why-dependency-injection)
|
||||
- [为什么依赖注入?](#why-dependency-injection)
|
||||
- [Angular dependency injection](#angular-dependency-injection)
|
||||
- [Angular依赖注入](#angular-dependency-injection)
|
||||
- [Injector providers](#injector-providers)
|
||||
- [注入器提供商](#injector-providers)
|
||||
- [Dependency injection tokens](#dependency-injection-tokens)
|
||||
- [依赖注入令牌](#dependency-injection-tokens)
|
||||
- [Summary](#summary)
|
||||
- [总结](#summary)
|
||||
|
||||
p Run the #[+liveExampleLink2()].
|
||||
p 运行#[+liveExampleLink2('在线例子')].
|
||||
|
||||
.l-main-section#why-di
|
||||
:marked
|
||||
|
@ -115,13 +121,12 @@ p Run the #[+liveExampleLink2()].
|
|||
|
||||
我们该如何让`Car`更强壮、有弹性以及可测试?
|
||||
|
||||
That's super easy. We change our `Car` constructor to a version with DI:
|
||||
|
||||
答案超级简单。我们把`Car`的构造函数改造成使用DI的版本:
|
||||
|
||||
<a id="ctor-injection"></a>
|
||||
That's super easy. We change our `Car` constructor to a version with DI:
|
||||
|
||||
<a id="ctor-injection"></a>
|
||||
答案超级简单。我们把`Car`的构造函数改造成使用DI的版本:
|
||||
|
||||
+makeTabs(
|
||||
'dependency-injection/ts/app/car/car.ts, dependency-injection/ts/app/car/car-no-di.ts',
|
||||
'car-ctor, car-ctor',
|
||||
|
@ -333,10 +338,15 @@ block ctor-syntax
|
|||
[separate concern](https://en.wikipedia.org/wiki/Separation_of_concerns),
|
||||
we suggest that you
|
||||
write the service code in its own file.
|
||||
|
||||
因为服务是一个[分离关注点](https://en.wikipedia.org/wiki/Separation_of_concerns),
|
||||
我们建议你把服务代码放到它自己的文件里。
|
||||
+ifDocsFor('ts')
|
||||
:marked
|
||||
See [this note](#one-class-per-file) for details.
|
||||
|
||||
到[这个笔记](#one-class-per-file)看更多信息。
|
||||
|
||||
+makeExample('dependency-injection/ts/app/heroes/hero.service.1.ts',null, 'app/heroes/hero.service.ts' )
|
||||
|
||||
:marked
|
||||
|
@ -352,6 +362,8 @@ block ctor-syntax
|
|||
Notice the `@Injectable()` #{_decorator} above the service class.
|
||||
We'll discuss its purpose [shortly](#injectable).
|
||||
|
||||
注意服务类上面这个`@Injectable()`装饰器。我们[很快](#injectable)会讨论它的用途。
|
||||
|
||||
- var _perhaps = _docsFor == 'dart' ? '' : 'perhaps';
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -467,7 +479,7 @@ block ctor-syntax
|
|||
.l-sub-section
|
||||
:marked
|
||||
#### Focus on the constructor
|
||||
### 来看构造函数
|
||||
#### 来看构造函数
|
||||
|
||||
Adding a parameter to the constructor isn't all that's happening here.
|
||||
|
||||
|
@ -482,19 +494,28 @@ block ctor-syntax
|
|||
Also recall that the parent component (`HeroesComponent`)
|
||||
has `providers` information for `HeroService`.
|
||||
|
||||
注意构造函数参数有类型`HeroService`,并且`HeroListComponent`类有一个`@Component`装饰器
|
||||
(往上翻可以确认)。另外,记得父级组件(`HeroesComponent`)有`HeroService`的`providers`信息。
|
||||
|
||||
The constructor parameter type, the `@Component` #{_decorator},
|
||||
and the parent's `providers` information combine to tell the
|
||||
Angular injector to inject an instance of
|
||||
`HeroService` whenever it creates a new `HeroListComponent`.
|
||||
|
||||
该构造函数类型、`@Component`装饰器、父级的`providers`信息这三个合起来,一起告诉Angular的注入器,在任何时候新建一个新的`HeroListComponent`的时候,注入一个`HeroService`的实例。
|
||||
|
||||
#di-metadata
|
||||
:marked
|
||||
### Implicit injector creation
|
||||
|
||||
### 显性注入器的创建
|
||||
|
||||
When we introduced the idea of an injector above, we showed how to
|
||||
use it to create a new `Car`. Here we also show how such an injector
|
||||
would be explicitly created:
|
||||
|
||||
当我们在上面介绍注入器的时候,我们展示了如何使用它创建一个新`Car`。这里,我们也展示一下如何显性的创建这样的注入器:
|
||||
|
||||
+makeExample('dependency-injection/ts/app/car/car-injector.ts','injector-create-and-call')(format=".")
|
||||
|
||||
:marked
|
||||
|
@ -587,12 +608,15 @@ block ctor-syntax
|
|||
//- FIXME refer to Dart API when that page becomes available.
|
||||
- var injMetaUrl = 'https://angular.io/docs/ts/latest/api/core/index/InjectableMetadata-class.html';
|
||||
h3#injectable Why @Injectable()?
|
||||
h3#injectable 为何@Injectable()?
|
||||
:marked
|
||||
**<a href="#{injMetaUrl}">@Injectable()</a>** marks a class as available to an
|
||||
injector for instantiation. Generally speaking, an injector will report an
|
||||
error when trying to instantiate a class that is not marked as
|
||||
`@Injectable()`.
|
||||
|
||||
**<a href="#{injMetaUrl}">@Injectable()</a>**标志着一个类可以被一个注入器实例化。通常来讲,在试图实例化一个没有被标识为`@Injectable()`的类时候,注入器将会报告错误。
|
||||
|
||||
block injectable-not-always-needed-in-ts
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -602,21 +626,31 @@ block injectable-not-always-needed-in-ts
|
|||
We need it because Angular requires constructor parameter metadata
|
||||
in order to inject a `Logger`.
|
||||
|
||||
在这里,我们可以在我们第一版的`HeroService`里面省略`@Injectable()`,因为它没有注入的参数。但是现在我们必须要有它,因为我们的服务有了一个注入的依赖。我们需要它,因为Angular需要构造函数参数的元数据来注入一个`Logger`。
|
||||
|
||||
.callout.is-helpful
|
||||
header Suggestion: add @Injectable() to every service class
|
||||
header 建议:为每一个服务类都添加@Injectable()
|
||||
:marked
|
||||
We recommend adding `@Injectable()` to every service class, even those that don't have dependencies
|
||||
and, therefore, do not technically require it. Here's why:
|
||||
|
||||
我们建议为每个服务类都添加`@Injectable()`,包括那些没有依赖所以技术上不需要它的。因为:
|
||||
|
||||
ul(style="font-size:inherit")
|
||||
li <b>Future proofing:</b> No need to remember <code>@Injectable()</code> when we add a dependency later.
|
||||
li <b>面向未来:</b> 没有必要记得在后来添加了一个依赖的时候添加<code>@Injectable()</code>。
|
||||
li <b>Consistency:</b> All services follow the same rules, and we don't have to wonder why #{_a} #{_decorator} is missing.
|
||||
li <b>一致性:</b>所有的服务都遵循同样的规则,并且我们不需要考虑为什么少一个装饰器。
|
||||
|
||||
|
||||
:marked
|
||||
Injectors are also responsible for instantiating components
|
||||
like `HeroesComponent`. Why haven't we marked `HeroesComponent` as
|
||||
`@Injectable()`?
|
||||
|
||||
注入器同时负责实例化像`HerosComponent`这样的组件。为什么我们不标记`HerosComponent`为`@Injectable()`呢?
|
||||
|
||||
We *can* add it if we really want to. It isn't necessary because the
|
||||
`HeroesComponent` is already marked with `@Component`, and this
|
||||
!{_decorator} class (like `@Directive` and `@Pipe`, which we'll learn about later)
|
||||
|
@ -624,6 +658,10 @@ block injectable-not-always-needed-in-ts
|
|||
fact `InjectableMetadata` #{_decorator}s that
|
||||
identify a class as a target for instantiation by an injector.
|
||||
|
||||
如果真的想要这样做,我们*可以*添加它。但是这不是必须的,因为`HerosComponent`已经被`@Component`标识,这个装饰器类(像`@Directive`和`@Pipe`一样,我们一会儿将会学到)
|
||||
是一个<a href="#{injMetaUrl}">InjectableMetadata</a>的子类型。实际上,`InjectableMetadata`装饰器标识着一个类是注入器实例化的目标。
|
||||
|
||||
|
||||
block ts-any-decorator-will-do
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -633,6 +671,10 @@ block ts-any-decorator-will-do
|
|||
But of course, it is more meaningful to mark a class using the appropriate
|
||||
<a href="#{injMetaUrl}">InjectableMetadata</a> #{_decorator}.
|
||||
|
||||
注入器使用一个类的构造元数据来决定依赖类型,该构造元数据就是构造函数的参数类型所标识的。
|
||||
TypeScript为任何带有一个装饰器的类生成这样的元数据,任何装饰器都生成。
|
||||
当然,使用一个合适的<a href="#{injMetaUrl}">InjectableMetadata</a>装饰器来标识一个类更加有意义。
|
||||
|
||||
.callout.is-critical
|
||||
header Always include the parentheses
|
||||
|
||||
|
@ -665,6 +707,8 @@ block ts-any-decorator-will-do
|
|||
|
||||
Our logger service is quite simple:
|
||||
|
||||
我们的日志服务很简单:
|
||||
|
||||
+makeExample('dependency-injection/ts/app/logger.service.ts', null, 'app/logger.service.ts')
|
||||
|
||||
block real-logger
|
||||
|
@ -675,6 +719,8 @@ block real-logger
|
|||
so we put it in the project's `#{_appDir}` folder, and
|
||||
we register it in the `providers` #{_array} of the metadata for our application root component, `AppComponent`.
|
||||
|
||||
我们比较可能在整个应用程序的任何地方都需要一样的日志服务,所以我们把它放到项目的`#{_appDir}`目录,并在应用程序根组件`AppComponent`的元数据的`providers`数组里面注册它。
|
||||
|
||||
+makeExcerpt('app/providers.component.ts','providers-logger','app/app.component.ts (excerpt)')
|
||||
|
||||
:marked
|
||||
|
@ -683,9 +729,6 @@ block real-logger
|
|||
如果我们忘了注册这个日志服务,Angular会在首次查找这个日志服务时,抛出一个异常。
|
||||
|
||||
code-example(format="nocode").
|
||||
EXCEPTION: No provider for Logger! (HeroListComponent -> HeroService -> Logger)
|
||||
|
||||
|
||||
EXCEPTION: No provider for Logger! (HeroListComponent -> HeroService -> Logger)
|
||||
(异常:Logger类没有供应商!(HeroListComponent -> HeroService -> Logger))
|
||||
|
||||
|
@ -755,18 +798,22 @@ code-example(format="nocode").
|
|||
|
||||
//- Dart limitation: the provide function isn't const so it cannot be used in an annotation.
|
||||
- var __andProvideFn = _docsFor == 'dart' ? '' : 'and <i>provide</i> object literal';
|
||||
- var __andProvideFn = _docsFor == 'dart' ? '' : '和 <i>provide</i> 对象';
|
||||
#provide
|
||||
:marked
|
||||
### The *Provider* class !{__andProvideFn}
|
||||
|
||||
### *Provider* 类!{__andProvideFn}
|
||||
:marked
|
||||
We wrote the `providers` #{_array} like this:
|
||||
|
||||
我们像下面一样写`providers`数组:
|
||||
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-1')
|
||||
|
||||
:marked
|
||||
This is actually a short-hand expression for a provider registration using the _provider_ object literal.
|
||||
|
||||
这实际上是使用_provider_对象常量注册供应商的缩写表达式。
|
||||
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-3a')
|
||||
|
||||
block provider-ctor-args
|
||||
|
@ -886,7 +933,6 @@ block dart-diff-const-metadata-ctor
|
|||
which makes this object play the logger role.
|
||||
|
||||
于是我们可以通过`useValue`选项来注册一个供应商,它会让这个对象直接扮演logger的角色。
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-7')(format=".")
|
||||
|
||||
- var stylePattern = { otl: /(useValue: \w*)/gm };
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-7', '', stylePattern)(format=".")
|
||||
|
@ -896,6 +942,8 @@ block dart-diff-const-metadata-ctor
|
|||
[Non-class dependencies](#non-class-dependencies) and
|
||||
[OpaqueToken](#opaquetoken) sections.
|
||||
|
||||
在[非类依赖](#non-class-dependencies)和[OpaqueToken](#opaquetoken)查看更多`useValue`的例子。
|
||||
|
||||
#factory-provider
|
||||
:marked
|
||||
### Factory providers
|
||||
|
@ -1065,17 +1113,18 @@ block dart-diff-const-metadata-ctor
|
|||
//- TODO: if function injection is useful explain or illustrate why.
|
||||
:marked
|
||||
### Non-class dependencies
|
||||
p
|
||||
| What if the dependency value isn't a class? Sometimes the thing we want to inject is a
|
||||
block non-class-dep-eg
|
||||
span string, function, or object.
|
||||
p
|
||||
| Applications often define configuration objects with lots of small facts
|
||||
| (like the title of the application or the address of a web API endpoint)
|
||||
block config-obj-maps
|
||||
| but these configuration objects aren't always instances of a class.
|
||||
| They can be object literals
|
||||
| such as this one:
|
||||
### 非类依赖
|
||||
|
||||
What if the dependency value isn't a class? Sometimes the thing we want to inject is a string, function, or object.
|
||||
|
||||
如果依赖值不是一个类呢?有时候我们想要注入的东西是一个字符串,函数或者对象。
|
||||
|
||||
Applications often define configuration objects with lots of small facts(like the title of the application or
|
||||
the address of a web API endpoint) but these configuration objects aren't always instances of a class.
|
||||
They can be object literals such as this one:
|
||||
|
||||
应用程序经常为很多很小的因素(比如应用程序的标题,或者一个网络API终点的地址)定义配置对象,但是这些配置对象不总是类的实例。
|
||||
他们可能是对象,比如下面这个:
|
||||
|
||||
+makeExample('dependency-injection/ts/app/app.config.ts','config','app/app-config.ts (excerpt)')(format='.')
|
||||
|
||||
|
@ -1167,12 +1216,16 @@ block dart-map-alternative
|
|||
#optional
|
||||
:marked
|
||||
## Optional dependencies
|
||||
## 可选依赖
|
||||
|
||||
Our `HeroService` *requires* a `Logger`, but what if it could get by without
|
||||
a logger?
|
||||
We can tell Angular that the dependency is optional by annotating the
|
||||
constructor argument with `@Optional()`:
|
||||
|
||||
我们的`HeroService`*需要*一个`Logger`,但是如果它可以不用一个Logger就行呢?
|
||||
我们可以通过把构造函数的参数标记为`@Optional()`来告诉Angular该依赖是可选的:
|
||||
|
||||
+ifDocsFor('ts')
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','import-optional', '')
|
||||
+makeExample('dependency-injection/ts/app/providers.component.ts','provider-10-ctor', '')(format='.')
|
||||
|
@ -1182,6 +1235,8 @@ block dart-map-alternative
|
|||
don't register a logger somewhere up the line, the injector will set the
|
||||
value of `logger` to null.
|
||||
|
||||
当使用`@Optional()`时,我们的代码必须要为一个空值做准备。如果我们不在组件或父级组件中注册一个`logger`的话,注入器会设置该`logger`的值为空null。
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Summary
|
||||
|
@ -1206,7 +1261,7 @@ block dart-map-alternative
|
|||
.l-main-section#explicit-injector
|
||||
:marked
|
||||
## Appendix: Working with injectors directly
|
||||
### 附录:直接使用注入器工作
|
||||
## 附录:直接使用注入器工作
|
||||
|
||||
We rarely work directly with an injector.
|
||||
Here's an `InjectorComponent` that does.
|
||||
|
|
Loading…
Reference in New Issue