修订完DI

This commit is contained in:
Zhicheng Wang 2017-04-15 21:27:07 +08:00
parent 8eff508115
commit e12b29a434
3 changed files with 41 additions and 21 deletions

View File

@ -956,7 +956,7 @@ a(id="tokens")
:marked :marked
## Provider token alternatives: the *class-interface* and *InjectionToken* ## Provider token alternatives: the *class-interface* and *InjectionToken*
## 备选提供商令牌:*类-接口*和*OpaqueToken* ## 备选提供商令牌:*类-接口*和*InjectionToken*
Angular dependency injection is easiest when the provider *token* is a class Angular dependency injection is easiest when the provider *token* is a class
that is also the type of the returned dependency object , orwhat you usually call the *service*. that is also the type of the returned dependency object , orwhat you usually call the *service*.

View File

@ -438,7 +438,7 @@ a#decoration
to a token. When you write `injector.get(Foo)`, the injector returns to a token. When you write `injector.get(Foo)`, the injector returns
the value associated with the token for the `Foo` class, typically an instance of `Foo` itself. the value associated with the token for the `Foo` class, typically an instance of `Foo` itself.
令牌是一个 Angular 中的类型 (`OpaqueToken`)。我们很少直接处理令牌。 令牌是一个 Angular 中的类型 (`InjectionToken`)。我们很少直接处理令牌。
绝大多数方法都接受类名 (`Foo`) 或字符串 ("foo") Angular 会把这些类名称和字符串转换成令牌。 绝大多数方法都接受类名 (`Foo`) 或字符串 ("foo") Angular 会把这些类名称和字符串转换成令牌。
当调用`injector.get(Foo)`时,注入器返回用`Foo`类生成的令牌所对应的依赖值,该依赖值通常是`Foo`类的实例。 当调用`injector.get(Foo)`时,注入器返回用`Foo`类生成的令牌所对应的依赖值,该依赖值通常是`Foo`类的实例。

View File

@ -141,7 +141,7 @@ block includes
To understand why dependency injection is so important, consider an example without it. To understand why dependency injection is so important, consider an example without it.
Imagine writing the following code: Imagine writing the following code:
我们从下列代码开始 要想理解为什么依赖注入这么重要,就先来考虑不使用它的一个例子。想象下列代码
+makeExample('dependency-injection/ts/src/app/car/car-no-di.ts', 'car', 'src/app/car/car.ts (without DI)') +makeExample('dependency-injection/ts/src/app/car/car-no-di.ts', 'car', 'src/app/car/car.ts (without DI)')
@ -244,7 +244,7 @@ block includes
It just consumes them. It just consumes them.
发生了什么?我们把依赖的定义移到了构造函数中。 发生了什么?我们把依赖的定义移到了构造函数中。
`Car`类不再创建引擎或者轮胎。 `Car`类不再创建引擎`engine`或者轮胎`tires`
它仅仅“消费”它们。 它仅仅“消费”它们。
.l-sub-section .l-sub-section
@ -529,11 +529,12 @@ a#register-providers-ngmodule
a#register-providers-component a#register-providers-component
:marked :marked
### Registering providers in a component ### Registering providers in a component
### 在组件中注册提供商 ### 在组件中注册提供商
Here's a revised `HeroesComponent` that registers the `HeroService` in its `providers` array. Here's a revised `HeroesComponent` that registers the `HeroService` in its `providers` array.
下面是更新的`HerosComponent`它注册了`HeroService` 下面是更新的`HerosComponent`把`HeroService`注册到了它的`providers`数组中
+makeExample('src/app/heroes/heroes.component.1.ts', 'full', 'src/app/heroes/heroes.component.ts', stylePattern)(format='.') +makeExample('src/app/heroes/heroes.component.1.ts', 'full', 'src/app/heroes/heroes.component.ts', stylePattern)(format='.')
@ -566,7 +567,7 @@ a#ngmodule-vs-comp
:marked :marked
Also see *"Should I add app-wide providers to the root `AppModule` or the root `AppComponent`?"* in the [NgModule FAQ](../cookbook/ngmodule-faq.html#q-root-component-or-module). Also see *"Should I add app-wide providers to the root `AppModule` or the root `AppComponent`?"* in the [NgModule FAQ](../cookbook/ngmodule-faq.html#q-root-component-or-module).
参见 [NgModule FAQ](../cookbook/ngmodule-faq.html#root-component-or-module) 一章的 参见 [NgModule FAQ](../cookbook/ngmodule-faq.html#q-root-component-or-module) 一章的
**我该把“全应用级”提供商加到根模块`AppModule`还是根组件`AppComponent`** **我该把“全应用级”提供商加到根模块`AppModule`还是根组件`AppComponent`**
@ -731,6 +732,8 @@ a#service-needs-service
a#injectable a#injectable
:marked :marked
### Why _@Injectable()_? ### Why _@Injectable()_?
### 为什么要用 _@Injectable()_?
**<a href="../api/core/index/Injectable-decorator.html">@Injectable()</a>** marks a class as available to an **<a href="../api/core/index/Injectable-decorator.html">@Injectable()</a>** marks a class as available to an
injector for instantiation. Generally speaking, an injector reports an injector for instantiation. Generally speaking, an injector reports an
@ -753,7 +756,10 @@ a#injectable
我们需要它,因为 Angular 需要构造函数参数的元数据来注入一个`Logger`。 我们需要它,因为 Angular 需要构造函数参数的元数据来注入一个`Logger`。
.callout.is-helpful .callout.is-helpful
header Suggestion: add @Injectable() to every service classheader 建议:为每个服务类都添加 @Injectable() header Suggestion: add @Injectable() to every service class
header 建议:为每个服务类都添加 @Injectable()
:marked :marked
Consider adding `@Injectable()` to every service class, even those that don't have dependencies Consider 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:
@ -788,7 +794,7 @@ a#injectable
我们**可以**添加它。但是没有必要,因为`HerosComponent`已经有`@Component`装饰器了, 我们**可以**添加它。但是没有必要,因为`HerosComponent`已经有`@Component`装饰器了,
`@Component`(和随后将会学到的`@Directive`和`@Pipe`一样)是 <a href="../api/core/index/Injectable-decorator.html">Injectable</a> 的子类型。 `@Component`(和随后将会学到的`@Directive`和`@Pipe`一样)是 <a href="../api/core/index/Injectable-decorator.html">Injectable</a> 的子类型。
实际上,正是这些`Injectable`装饰器是把一个类标识为注入器实例化的目标。 实际上,正是这些`@Injectable()`装饰器是把一个类标识为注入器实例化的目标。
.l-sub-section .l-sub-section
:marked :marked
@ -815,8 +821,8 @@ a#injectable
<a href="../api/core/index/Injectable-decorator.html">@Injectable()</a> decorator <a href="../api/core/index/Injectable-decorator.html">@Injectable()</a> decorator
to make the intent clear. to make the intent clear.
当然,任何装饰器都会触发这个效果,用 <a href="../api/core/index/Injectable-decorator.html">Injectable</a> 来标识服务 当然,任何装饰器都会触发这个效果,用 <a href="../api/core/index/Injectable-decorator.html">@Injectable()</a> 来标识服务
只是让这一意图更明显。 只是为了让这一意图更明显。
.callout.is-critical .callout.is-critical
header Always include the parentheses header Always include the parentheses
@ -833,9 +839,13 @@ a#injectable
.l-main-section#logger-service .l-main-section#logger-service
:marked :marked
## Creating and registering a logger service ## Creating and registering a logger service
## 创建和注册日志服务 ## 创建和注册日志服务
Inject a logger into `HeroService` in two steps:要把日志服务注入到`HeroService`中需要两步: Inject a logger into `HeroService` in two steps:
要把日志服务注入到`HeroService`中需要两步:
1. Create the logger service. 1. Create the logger service.
创建日志服务。 创建日志服务。
@ -864,6 +874,7 @@ a#injectable
If you forget to register the logger, Angular throws an exception when it first looks for the logger: If you forget to register the logger, Angular throws an exception when it first looks for the 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)
(异常Logger类没有提供商(HeroListComponent -> HeroService -> Logger)) (异常Logger类没有提供商(HeroListComponent -> HeroService -> Logger))
@ -1071,7 +1082,7 @@ a#value-provider
[Non-class dependencies](#non-class-dependencies) and [Non-class dependencies](#non-class-dependencies) and
[InjectionToken](#injection-token) sections. [InjectionToken](#injection-token) sections.
查看更多`useValue`的例子,见[非类依赖](#non-class-dependencies)和 [OpaqueToken](#opaquetoken) 查看更多`useValue`的例子,见[非类依赖](#non-class-dependencies)和 [InjectionToken](#injection-token)部分
#factory-provider #factory-provider
:marked :marked
@ -1099,7 +1110,7 @@ a#value-provider
Only authorized users should see secret heroes. Only authorized users should see secret heroes.
下面通过添加新的业务需求来说明这一点: 下面通过添加新的业务需求来说明这一点:
HeroService 必须对普通用户隐藏掉*秘密*英雄。 `HeroService` 必须对普通用户隐藏掉*秘密*英雄。
只有授权用户才能看到秘密英雄。 只有授权用户才能看到秘密英雄。
Like the `EvenBetterLogger`, the `HeroService` needs a fact about the user. Like the `EvenBetterLogger`, the `HeroService` needs a fact about the user.
@ -1241,15 +1252,16 @@ p
| string, function, or object. | string, function, or object.
p 如果依赖值不是一个类呢?有时候想要注入的东西是一个字符串,函数或者对象。 p 如果依赖值不是一个类呢?有时候想要注入的东西是一个字符串,函数或者对象。
p p
| Applications often define configuration objects with lots of small facts | Applications often define configuration objects with lots of small facts
| (like the title of the application or the address of a web API endpoint) | (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. | but these configuration objects aren't always instances of a class.
| They can be object literals such as this one: | They can be object literals such as this one:
p 应用程序经常为很多很小的因素定义配置对象例如应用程序的标题或网络API终点的地址 p
block config-obj-maps | 应用程序经常为很多很小的因素定义配置对象例如应用程序的标题或网络API终点的地址
| 但是这些配置对象不总是类的实例,它们可能是对象,如下面这个: | 但是这些配置对象不总是类的实例,它们可能是对象,如下面这个:
+makeExample('dependency-injection/ts/src/app/app.config.ts','config','src/app/app-config.ts (excerpt)')(format='.') +makeExample('dependency-injection/ts/src/app/app.config.ts','config','src/app/app-config.ts (excerpt)')(format='.')
@ -1277,8 +1289,11 @@ p 应用程序经常为很多很小的因素定义配置对象(例如应用程
cannot use a TypeScript interface as a token: cannot use a TypeScript interface as a token:
`CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌: `CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
+makeExample('dependency-injection/ts/src/app/providers.component.ts','providers-9-interface')(format=".") +makeExample('dependency-injection/ts/src/app/providers.component.ts','providers-9-interface')(format=".")
+makeExample('dependency-injection/ts/src/app/providers.component.ts','provider-9-ctor-interface')(format=".") +makeExample('dependency-injection/ts/src/app/providers.component.ts','provider-9-ctor-interface')(format=".")
:marked :marked
That seems strange if you're used to dependency injection in strongly typed languages, where That seems strange if you're used to dependency injection in strongly typed languages, where
an interface is the preferred dependency lookup key. an interface is the preferred dependency lookup key.
@ -1306,13 +1321,17 @@ a#injection-token
定义方式是这样的: 定义方式是这样的:
+makeExample('dependency-injection/ts/src/app/app.config.ts','token')(format='.') +makeExample('dependency-injection/ts/src/app/app.config.ts','token')(format='.')
:marked :marked
The type parameter, while optional, conveys the dependency's type to developers and tooling. The type parameter, while optional, conveys the dependency's type to developers and tooling.
The token description is another developer aid. The token description is another developer aid.
类型参数,虽然是可选的,但可以向开发者和开发工具传达类型信息。
而且这个令牌的描述信息也可以为开发者提供帮助。
Register the dependency provider using the `InjectionToken` object: Register the dependency provider using the `InjectionToken` object:
使用这个`OpaqueToken`对象注册依赖的提供商: 使用这个`InjectionToken`对象注册依赖的提供商:
+makeExample('dependency-injection/ts/src/app/providers.component.ts','providers-9')(format=".") +makeExample('dependency-injection/ts/src/app/providers.component.ts','providers-9')(format=".")
@ -1360,7 +1379,7 @@ a#injection-token
value of `logger` to null. value of `logger` to null.
当使用`@Optional()`时,代码必须准备好如何处理空值。 当使用`@Optional()`时,代码必须准备好如何处理空值。
如果其它的代码没有注册一个 logger注入器会设置该`logger`的值为空 null。 如果其它的代码没有注册一个 `logger`,注入器会设置该`logger`的值为空 null。
.l-main-section .l-main-section
:marked :marked
@ -1405,20 +1424,21 @@ a#injection-token
The component then asks the injected injector for the services it wants in `ngOnInit()`. The component then asks the injected injector for the services it wants in `ngOnInit()`.
在这个例子中Angular 把组件自身的`Injector`注入到了组件的构造函数中。 在这个例子中Angular 把组件自身的`Injector`注入到了组件的构造函数中。
然后,组件向注入的注入器请求它所需的服务。 然后,组件在`ngOnInit()`中向注入的注入器请求它所需的服务。
Note that the services themselves are not injected into the component. Note that the services themselves are not injected into the component.
They are retrieved by calling `injector.get()`. They are retrieved by calling `injector.get()`.
注意,这些服务本身没有注入到组件,它们是通过调用`injector.get`获得的。 注意,这些服务本身没有注入到组件,它们是通过调用`injector.get()`获得的。
The `get()` method throws an error if it can't resolve the requested service. The `get()` method throws an error if it can't resolve the requested service.
You can call `get()` with a second parameter, which is the value to return if the service You can call `get()` with a second parameter, which is the value to return if the service
is not found. Angular can't find the service if it's not registered with this or any ancestor injector. is not found. Angular can't find the service if it's not registered with this or any ancestor injector.
`get()`方法如果不能解析所请求的服务,会抛出异常。 `get()`方法如果不能解析所请求的服务,会抛出异常。
调用`get`时,还可以使用第二个参数,一旦获取的服务 (`ROUS`) 没有在当前或任何祖先注入器中注册过, 调用`get()`时,还可以使用第二个参数,一旦获取的服务没有在当前或任何祖先注入器中注册过,
就把它作为返回值。 就把它作为返回值。
.l-sub-section .l-sub-section
:marked :marked
The technique is an example of the The technique is an example of the