diff --git a/public/docs/ts/latest/guide/dependency-injection.jade b/public/docs/ts/latest/guide/dependency-injection.jade index 5cc69da098..3efe0af3d9 100644 --- a/public/docs/ts/latest/guide/dependency-injection.jade +++ b/public/docs/ts/latest/guide/dependency-injection.jade @@ -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的版本: - That's super easy. We change our `Car` constructor to a version with DI: + + 答案超级简单。我们把`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 **@Injectable()** 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()`. + **@Injectable()**标志着一个类可以被一个注入器实例化。通常来讲,在试图实例化一个没有被标识为`@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 Future proofing: No need to remember @Injectable() when we add a dependency later. + li 面向未来: 没有必要记得在后来添加了一个依赖的时候添加@Injectable()。 li Consistency: All services follow the same rules, and we don't have to wonder why #{_a} #{_decorator} is missing. + li 一致性:所有的服务都遵循同样的规则,并且我们不需要考虑为什么少一个装饰器。 + :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`一样,我们一会儿将会学到) + 是一个InjectableMetadata的子类型。实际上,`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 InjectableMetadata #{_decorator}. + 注入器使用一个类的构造元数据来决定依赖类型,该构造元数据就是构造函数的参数类型所标识的。 + TypeScript为任何带有一个装饰器的类生成这样的元数据,任何装饰器都生成。 + 当然,使用一个合适的InjectableMetadata装饰器来标识一个类更加有意义。 + .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 provide object literal'; +- var __andProvideFn = _docsFor == 'dart' ? '' : '和 provide 对象'; #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.