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
1 changed files with 78 additions and 23 deletions

View File

@ -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
| &nbsp;but these configuration objects aren't always instances of a class.
| They can be object literals
| &nbsp;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) &nbsp;but these configuration objects aren't always instances of a class.
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='.')
@ -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.