patch up guide\dependency-injection.jade after official updates.

This commit is contained in:
Zhimin(Rex) YE 2016-06-04 19:54:25 +01:00
parent 633964ac2f
commit cb8818f171

View File

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