Merge pull request #165 from todoubaba/toh-pt4

Polish toh-pt4.jade (round 2)
This commit is contained in:
Rex 2016-12-01 21:17:10 +00:00 committed by GitHub
commit e56cca9c79
1 changed files with 86 additions and 78 deletions

View File

@ -10,19 +10,19 @@ include ../_util-fns
Instead, we'll create a single reusable data service and learn to Instead, we'll create a single reusable data service and learn to
inject it in the components that need it. inject it in the components that need it.
将来会有更多的组件访问英雄数据,但我们不想一遍又一遍的复制粘贴同样的代码。 将来会有更多的组件访问英雄数据,我们不想一遍一遍地复制粘贴同样的代码。
我们的替代方案是,创建一个单一的、可复用的数据服务,然后学着把它注入到那些想用它的组件中去。 解决方案是,创建一个单一的、可复用的数据服务,然后学着把它注入到那些需要它的组件中去。
Refactoring data access to a separate service keeps the component lean and focused on supporting the view. Refactoring data access to a separate service keeps the component lean and focused on supporting the view.
It also makes it easier to unit test the component with a mock service. It also makes it easier to unit test the component with a mock service.
我们将重构数据访问代码,把它隔离到一个独立的服务中去,让组件尽可能保持精简,专注于为视图提供支持。 我们将重构数据访问代码,把它隔离到一个独立的服务中去,让组件尽可能保持精简,专注于为视图提供支持。
在这种方式下,借助mock服务来对组件进行单元测试也会更容易。 在这种方式下,借助模拟服务来对组件进行单元测试也会更容易。
Because data services are invariably asynchronous, Because data services are invariably asynchronous,
we'll finish the chapter with a **!{_Promise}**-based version of the data service. we'll finish the chapter with a **!{_Promise}**-based version of the data service.
因为数据服务通常都是异步的,我们将在本章创建一个基于**承诺Promise**的数据服务。 因为数据服务通常都是异步的,我们将在本章创建一个基于**承诺 (Promise)**的数据服务。
Run the <live-example></live-example> for this part. Run the <live-example></live-example> for this part.
@ -37,7 +37,7 @@ include ../_util-fns
Before we continue with our Tour of Heroes, lets verify we have the following structure. Before we continue with our Tour of Heroes, lets verify we have the following structure.
If not, well need to go back and follow the previous chapters. If not, well need to go back and follow the previous chapters.
在继续《英雄指南》之前,先检查一下,是否已经有如下目录结构。如果没有,你得先回上一章,看看错过了哪里。 在继续《英雄指南》之前,先检查一下,是否已经有如下目录结构。如果没有,回上一章,看看错过了哪里。
.filetree .filetree
.file angular-tour-of-heroes .file angular-tour-of-heroes
@ -64,7 +64,7 @@ include ../_util-fns
Open a terminal/console window. Open a terminal/console window.
Start the TypeScript compiler, watch for changes, and start our server by entering the command: Start the TypeScript compiler, watch for changes, and start our server by entering the command:
打开terminal/console窗口启动TypeScript编译器,它会监视文件变更,并启动开发服务器。只要敲: 打开终端/控制台窗口,启动 TypeScript 编译器,它会监视文件变更,并启动开发服务器。只要敲:
code-example(language="bash"). code-example(language="bash").
npm start npm start
@ -84,28 +84,29 @@ code-example(language="bash").
Soon we'll add a dashboard with the top performing heroes and create a separate view for editing hero details. Soon we'll add a dashboard with the top performing heroes and create a separate view for editing hero details.
All three views need hero data. All three views need hero data.
客户向我们描绘了本应用更大的目标。 客户向我们描绘了本应用更大的目标:想要在不同的页面中用多种方式显示英雄。
它们说,想要在不同的页面中用多种方式显示英雄。
现在我们已经能从列表中选择一个英雄了,但这还不够。 现在我们已经能从列表中选择一个英雄了,但这还不够。
很快,我们将添加一个仪表盘来显示表现最好的英雄,并创建一个独立视图来编辑英雄的详情。 很快,我们将添加一个仪表盘来显示表现最好的英雄,并创建一个独立视图来编辑英雄的详情。
所有这些视图都需要英雄数据。 所有这些视图都需要英雄数据。
At the moment the `AppComponent` defines mock heroes for display. At the moment the `AppComponent` defines mock heroes for display.
We have at least two objections. We have at least two objections.
First, defining heroes is not the component's job. First, defining heroes is not the component's job.
Second, we can't easily share that list of heroes with other components and views. Second, we can't easily share that list of heroes with other components and views.
目前,`AppComponent`显示的是mock英雄数据。 目前,`AppComponent`显示的是模拟数据。
我们可改进的地方至少有两个:首先,定义英雄的数据不该是组件的任务。其次,想把这份英雄列表的数据共享给其它组件和视图可不那么容易。 至少有两个地方可以改进:
首先,定义英雄的数据不该是组件的任务;
其次,想把这份英雄列表的数据共享给其它组件和视图可不那么容易。
We can refactor this hero data acquisition business to a single service that provides heroes, and We can refactor this hero data acquisition business to a single service that provides heroes, and
share that service with all components that need heroes. share that service with all components that need heroes.
我们可以把获取英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并这个服务在所有需要英雄数据的组件间共享。 我们可以把获取英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并把服务在所有需要英雄数据的组件间共享。
### Create the HeroService ### Create the HeroService
### 创建HeroService ### 创建 HeroService
Create a file in the `app` folder called `hero.service.ts`. Create a file in the `app` folder called `hero.service.ts`.
@ -117,14 +118,14 @@ code-example(language="bash").
If the service name were multi-word, we'd spell the base filename in lower [dash-case](../guide/glossary.html#dash-case). If the service name were multi-word, we'd spell the base filename in lower [dash-case](../guide/glossary.html#dash-case).
The `SpecialSuperHeroService` would be defined in the `special-super-hero.service.ts` file. The `SpecialSuperHeroService` would be defined in the `special-super-hero.service.ts` file.
我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。 我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。
如果服务名称包含多个单词,我们就把基本名部分写成中线形式[dash-case](../guide/glossary.html#dash-case) 如果服务名称包含多个单词,我们就把基本名部分写成中线形式 ([dash-case](../guide/glossary.html#dash-case))
如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。 如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。
:marked :marked
We name the class `HeroService` and export it for others to import. We name the class `HeroService` and export it for others to import.
我们把这个类命名为`HeroService`,并导出它,以供别人使用。 我们把这个类命名为`HeroService`,并导出它,以供别人使用。
+makeExample('toh-4/ts/app/hero.service.1.ts', 'empty-class', 'app/hero.service.ts (starting point)')(format=".") +makeExample('toh-4/ts/app/hero.service.1.ts', 'empty-class', 'app/hero.service.ts (starting point)')(format=".")
@ -135,7 +136,7 @@ code-example(language="bash").
Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator. Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator.
注意,我们引入了Angular的`Injectable`函数,并通过`@Injectable()`装饰器使用这个函数。 注意,我们导入了 Angular 的`Injectable`函数,并作为`@Injectable()`装饰器使用这个函数。
.callout.is-helpful .callout.is-helpful
:marked :marked
@ -147,18 +148,21 @@ code-example(language="bash").
TypeScript sees the `@Injectable()` decorator and emits metadata about our service, TypeScript sees the `@Injectable()` decorator and emits metadata about our service,
metadata that Angular may need to inject other dependencies into this service. metadata that Angular may need to inject other dependencies into this service.
当TypeScript看到`@Injectable()`装饰器时就会记下本服务的元数据。如果Angular需要往这个服务中注入其它依赖就会使用这些元数据。 当 TypeScript 看到`@Injectable()`装饰器时,就会记下本服务的元数据。
如果 Angular 需要往这个服务中注入其它依赖,就会使用这些元数据。
The `HeroService` doesn't have any dependencies *at the moment*. Add the decorator anyway. The `HeroService` doesn't have any dependencies *at the moment*. Add the decorator anyway.
It is a "best practice" to apply the `@Injectable()` decorator *from the start* It is a "best practice" to apply the `@Injectable()` decorator *from the start*
both for consistency and for future-proofing. both for consistency and for future-proofing.
此刻,`HeroService`还没有任何依赖,但我们还是得加上这个装饰器。作为一项最佳实践,无论是出于提高统一性还是减少变更的目的,都应该从一开始就加上`@Injectable()`装饰器。 *此时*`HeroService`还没有任何依赖,但我们还是得加上这个装饰器。
作为一项最佳实践,无论是出于提高统一性还是减少变更的目的,
都应该从一开始就加上`@Injectable()`装饰器。
:marked :marked
### Getting Heroes ### Getting Heroes
### 获取英雄 ### 获取英雄数据
Add a `getHeroes` method stub. Add a `getHeroes` method stub.
@ -178,7 +182,7 @@ code-example(language="bash").
数据使用者并不知道本服务会如何获取数据。 数据使用者并不知道本服务会如何获取数据。
我们的`HeroService`服务可以从任何地方获取英雄的数据。 我们的`HeroService`服务可以从任何地方获取英雄的数据。
它可以从网络服务器获取,可以从浏览器的局部存储区获取,也可以是mock的数据源。 它可以从网络服务器获取,可以从浏览器的局部存储区获取,也可以从模拟的数据源。
That's the beauty of removing data access from the component. That's the beauty of removing data access from the component.
We can change our minds about the implementation as often as we like, We can change our minds about the implementation as often as we like,
@ -189,25 +193,26 @@ code-example(language="bash").
### Mock Heroes ### Mock Heroes
### Mock英雄数据 ### 模拟英雄数据
We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either. We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either.
We'll move the mock data to its own file. We'll move the mock data to its own file.
我们曾在`AppComponent`组件中写过mock版的英雄数据。它不该在那里但也不该在*这里*我们得把mock数据移到它自己的文件中去。 我们曾在`AppComponent`组件中写过模拟数据。它不该在那里,但也不该在*这里*
我们应把模拟数据移到它自己的文件中去。
Cut the `HEROES` array from `app.component.ts` and paste it to a new file in the `app` folder named `mock-heroes.ts`. Cut the `HEROES` array from `app.component.ts` and paste it to a new file in the `app` folder named `mock-heroes.ts`.
We copy the `import {Hero} ...` statement as well because the heroes array uses the `Hero` class. We copy the `import {Hero} ...` statement as well because the heroes array uses the `Hero` class.
从`app.component.ts`文件中剪切`HEROS`数组,把它粘贴到`app`目录下一个名叫`mock-heroes.ts`的文件中。 从`app.component.ts`文件中剪切`HEROS`数组,把它粘贴到`app`目录下一个名叫`mock-heroes.ts`的文件中。
我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。 还要复制`import {Hero}...`语句,因为我们的英雄数组用到了`Hero`类。
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts') +makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts')
:marked :marked
We export the `HEROES` constant so we can import it elsewhere &mdash; such as our `HeroService`. We export the `HEROES` constant so we can import it elsewhere &mdash; such as our `HeroService`.
我们导出了`HEROES`常量,以便在其它地方导入它 —— 比如`HeroService`服务。 我们导出了`HEROES`常量,以便可以在其它地方导入它 &mdash; 例如`HeroService`服务。
Meanwhile, back in `app.component.ts` where we cut away the `HEROES` array, Meanwhile, back in `app.component.ts` where we cut away the `HEROES` array,
we leave behind an uninitialized `heroes` property: we leave behind an uninitialized `heroes` property:
@ -231,15 +236,15 @@ code-example(language="bash").
:marked :marked
### Use the Hero Service ### Use the Hero Service
### 使用HeroService服务 ### 使用 HeroService 服务
We're ready to use the `HeroService` in other components starting with our `AppComponent`. We're ready to use the `HeroService` in other components starting with our `AppComponent`.
我们可以在多个组件中使用HeroService服务了先从AppComponent开始。 我们可以在多个组件中使用 HeroService 服务了,先从 AppComponent 开始。
We begin, as usual, by importing the thing we want to use, the `HeroService`. We begin, as usual, by importing the thing we want to use, the `HeroService`.
通常,我们会从导入要用的东西开始,比如`HeroService`。 通常,我们先导入要用的东西,例如`HeroService`。
+makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import') +makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import')
@ -247,7 +252,7 @@ code-example(language="bash").
Importing the service allows us to *reference* it in our code. Importing the service allows us to *reference* it in our code.
How should the `AppComponent` acquire a runtime concrete `HeroService` instance? How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
导入这个服务让我们可以在代码中引用它。 导入这个服务让我们可以在代码中*引用*它。
`AppComponent`该如何在运行中获得一个具体的`HeroService`实例呢? `AppComponent`该如何在运行中获得一个具体的`HeroService`实例呢?
### Do we *new* the *HeroService*? No way! ### Do we *new* the *HeroService*? No way!
@ -256,29 +261,29 @@ code-example(language="bash").
We could create a new instance of the `HeroService` with `new` like this: We could create a new instance of the `HeroService` with `new` like this:
固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样: 尽管我们可以使用`new`来创建`HeroService`的实例,就像这样:
+makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".")
:marked :marked
That's a bad idea for several reasons including That's a bad idea for several reasons including
但这不是个好主意,有很多理由,如: 但这不是个好主意,有很多理由,如:
* Our component has to know how to create a `HeroService`. * Our component has to know how to create a `HeroService`.
If we ever change the `HeroService` constructor, If we ever change the `HeroService` constructor,
we'll have to find every place we create the service and fix it. we'll have to find every place we create the service and fix it.
Running around patching code is error prone and adds to the test burden. Running around patching code is error prone and adds to the test burden.
* 我们的组件将不得不弄清楚该如何创建`HeroService`。 我们的组件得弄清楚该如何创建`HeroService`。
如果有一天我们修改了`HeroService`的构造函数,我们不得不找出创建过此服务的每一处代码,并修改它。 如果有一天我们修改了`HeroService`的构造函数,我们不得不找出创建过此服务的每一处代码,并修改它。
而给代码打补丁的行为容易导致错误,并增加了测试的负担。 围着补丁代码转圈很容易导致错误,还会增加测试负担。
* We create a new service each time we use `new`. * We create a new service each time we use `new`.
What if the service should cache heroes and share that cache with others? What if the service should cache heroes and share that cache with others?
We couldn't do that. We couldn't do that.
* 我们每次使用`new`都会创建一个新的服务实例。 我们每次使用`new`都会创建一个新的服务实例。
如果这个服务需要缓存英雄列表,并把这个缓存共享给别人呢?怎么办? 如果这个服务需要缓存英雄列表,并把这个缓存共享给别人呢?怎么办?
没办法,做不到。 没办法,做不到。
@ -288,13 +293,13 @@ code-example(language="bash").
Will we need different mocked versions under test? Will we need different mocked versions under test?
Not easy. Not easy.
* 我们把`AppComponent`锁死在`HeroService`的一个特定实现中 我们把`AppComponent`锁定到`HeroService`的一个特定实现
我们很难在别的场景中把它换成别的实现。 我们很难在不同的场景中切换实现。
如,能离线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。 如,能离线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。
* What if ... what if ... Hey, we've got work to do!* * What if ... what if ... Hey, we've got work to do!*
* 如果……如果……嘿!这下我们可有得忙了! 如果……如果……嘿!这下我们可有得忙了!
We get it. Really we do. We get it. Really we do.
But it is so ridiculously easy to avoid these problems that there is no excuse for doing it wrong. But it is so ridiculously easy to avoid these problems that there is no excuse for doing it wrong.
@ -311,11 +316,11 @@ code-example(language="bash").
1. We add a constructor that also defines a private property. 1. We add a constructor that also defines a private property.
1. 我们添加了一个构造函数,同时还定义了一个私有属性。 添加一个构造函数,并定义一个私有属性。
1. We add to the component's `providers` metadata. 1. We add to the component's `providers` metadata.
1. 我们添加了组件的`providers`元数据 添加组件的`providers`元数据。
Here's the constructor: Here's the constructor:
@ -331,24 +336,24 @@ code-example(language="bash").
:marked :marked
Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`. Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`.
现在,Angular将会知道创建`AppComponent`实例时,需要先提供一个`HeroService`的实例。 现在,当创建`AppComponent`实例时,Angular 知道需要先提供一个`HeroService`的实例。
.l-sub-section .l-sub-section
:marked :marked
Learn more about Dependency Injection in the [Dependency Injection](../guide/dependency-injection.html) chapter. Learn more about Dependency Injection in the [Dependency Injection](../guide/dependency-injection.html) chapter.
要了解关于依赖注入的更多知识,请参见[依赖注入](../guide/dependency-injection.html)一章 更多依赖注入的信息,见[依赖注入](../guide/dependency-injection.html)。
:marked :marked
The *injector* does not know yet how to create a `HeroService`. The *injector* does not know yet how to create a `HeroService`.
If we ran our code now, Angular would fail with an error: If we ran our code now, Angular would fail with an error:
*注入器*还不知道该如何创建`HeroService`。 *注入器*还不知道该如何创建`HeroService`。
如果现在运行我们的代码Angular就会失败并报错 如果现在运行我们的代码Angular 就会失败,并报错:
code-example(format="nocode"). code-example(format="nocode").
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService) EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
(异常没有HeroService的提供商(AppComponent -> HeroService)) (异常:没有 HeroService 的提供商!(AppComponent -> HeroService))
:marked :marked
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**. We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
@ -356,7 +361,7 @@ code-example(format="nocode").
in the `@Component` call. in the `@Component` call.
我们还得注册一个`HeroService`**提供商**,来告诉*注入器*如何创建`HeroService`。 我们还得注册一个`HeroService`**提供商**,来告诉*注入器*如何创建`HeroService`。
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下: 要做到这一点,我们在`@Component`组件的元数据底部添加`providers`数组属性如下:
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers') +makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers')
@ -364,7 +369,7 @@ code-example(format="nocode").
The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`. The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
The `AppComponent` can use that service to get heroes and so can every child component of its component tree. The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
`providers`数组告诉Angular当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。 `providers`数组告诉 Angular当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。
`AppComponent`会使用那个服务来获取英雄列表,在它组件树中的每一个子组件也同样如此。 `AppComponent`会使用那个服务来获取英雄列表,在它组件树中的每一个子组件也同样如此。
a#child-component a#child-component
@ -375,7 +380,7 @@ a#child-component
We've got the service in a `heroService` private variable. Let's use it. We've got the service in a `heroService` private variable. Let's use it.
我们已经获得了此服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。 我们已经有了服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。
We pause to think. We can call the service and get the data in one line. We pause to think. We can call the service and get the data in one line.
@ -405,14 +410,15 @@ a#child-component
Years of experience and bitter tears have taught us to keep complex logic out of the constructor, Years of experience and bitter tears have taught us to keep complex logic out of the constructor,
especially anything that might call a server as a data access method is sure to do. especially anything that might call a server as a data access method is sure to do.
多年的经验和惨痛的教训教育我们,应该把复杂的逻辑扔到构造函数外面去,特别是那些需要从服务器获取数据的逻辑更是如此。 多年的经验和惨痛的教训教育我们,应该把复杂的逻辑扔到构造函数外面去,
特别是那些需要从服务器获取数据的逻辑更是如此。
The constructor is for simple initializations like wiring constructor parameters to properties. The constructor is for simple initializations like wiring constructor parameters to properties.
It's not for heavy lifting. We should be able to create a component in a test and not worry that it It's not for heavy lifting. We should be able to create a component in a test and not worry that it
might do real work &mdash; like calling a server! &mdash; before we tell it to do so. might do real work &mdash; like calling a server! &mdash; before we tell it to do so.
构造函数是为了简单的初始化工作而设计的,如把构造函数的参数赋值给属性。 构造函数是为了简单的初始化工作而设计的,如把构造函数的参数赋值给属性。
它的负担不应该过于沉重。我们应该能在测试中创建一个组件,而不用担心它会做实际的工作 —— 比如和服务器通讯,直到我们主动要求它做这些。 它的负担不应该过于沉重。我们应该能在测试中创建一个组件,而不用担心它会做实际的工作 &mdash; 例如和服务器通讯,直到我们主动要求它做这些。
If not the constructor, something has to call `getHeroes`. If not the constructor, something has to call `getHeroes`.
@ -422,18 +428,18 @@ a#child-component
Angular offers a number of interfaces for tapping into critical moments in the component lifecycle: Angular offers a number of interfaces for tapping into critical moments in the component lifecycle:
at creation, after each change, and at its eventual destruction. at creation, after each change, and at its eventual destruction.
这也不难。只要我们实现了Angular的 **ngOnInit** *生命周期钩子*Angular就会主动调用这个钩子。 这也不难。只要我们实现了 Angular 的 **ngOnInit** *生命周期钩子*Angular 就会主动调用这个钩子。
Angular提供了一些接口用来介入组件生命周期的几个关键时间点刚创建时、每次变化时以及最终被销毁时。 Angular提供了一些接口用来介入组件生命周期的几个关键时间点刚创建时、每次变化时以及最终被销毁时。
Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time. Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time.
每个接口都有唯一的一个方法。只要组件实现了这个方法Angular就会在合适的时机调用它。 每个接口都有唯一的一个方法。只要组件实现了这个方法Angular 就会在合适的时机调用它。
.l-sub-section .l-sub-section
:marked :marked
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter. Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
要了解关于生命周期钩子的更多知识,请参见 [生命周期钩子](../guide/lifecycle-hooks.html) 一章 更多生命周期钩子信息,见[生命周期钩子](../guide/lifecycle-hooks.html)。
:marked :marked
Here's the essential outline for the `OnInit` interface: Here's the essential outline for the `OnInit` interface:
@ -446,7 +452,8 @@ a#child-component
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
at the right time. In our case, we initialize by calling `getHeroes`. at the right time. In our case, we initialize by calling `getHeroes`.
我们写下带有初始化逻辑的`ngOnInit`方法然后留给Angular供其在正确的时机调用。在这个例子中我们通过调用`getHeroes`来完成初始化。 我们写了一个带有初始化逻辑的`ngOnInit`方法Angular会在适当的时候调用它。
在这个例子中,我们通过调用`getHeroes`来完成初始化。
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init') +makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init')
@ -476,16 +483,17 @@ a#child-component
:marked :marked
Ask for heroes and they are there in the returned result. Ask for heroes and they are there in the returned result.
请求英雄数据,并直接在结果中返回它 请求英雄数据,返回结果中就有它们了
Someday we're going to get heroes from a remote server. We dont call http yet, but we aspire to in later chapters. Someday we're going to get heroes from a remote server. We dont call http yet, but we aspire to in later chapters.
将来,我们会从远端服务器上获取英雄数据。我们还没调用http但在未来的章节中我们会希望这么做。 将来,我们打算从远端服务器上获取英雄数据。我们还没调用 http但在后面的章节中我们会希望这么做。
When we do, we'll have to wait for the server to respond and we won't be able to block the UI while we wait, When we do, we'll have to wait for the server to respond and we won't be able to block the UI while we wait,
even if we want to (which we shouldn't) because the browser won't block. even if we want to (which we shouldn't) because the browser won't block.
那时候我们不得不等待服务器返回并且在等待时我们没法阻塞UI响应即使我们想这么做也不应这么做也做不到因为浏览器不会阻塞。 那时候,我们不得不等待服务器响应,并且在等待过程中我们无法阻塞用户界面响应,
即使我们想这么做(也不应这么做)也做不到,因为浏览器不会阻塞。
We'll have to use some kind of asynchronous technique and that will change the signature of our `getHeroes` method. We'll have to use some kind of asynchronous technique and that will change the signature of our `getHeroes` method.
@ -503,15 +511,15 @@ a#child-component
We ask an asynchronous service to do some work and give it a callback function. We ask an asynchronous service to do some work and give it a callback function.
It does that work (somewhere) and eventually it calls our function with the results of the work or an error. It does that work (somewhere) and eventually it calls our function with the results of the work or an error.
**承诺** 就是 …… 好吧,它就是一个承诺 —— 在有了结果时,它承诺会回调我们。 **承诺** 就是 …… 好吧,它就是一个承诺在有了结果时,它承诺会回调我们。
我们请求一个异步服务去做点什么,并且给它一个回调函数。 我们请求一个异步服务去做点什么,并且给它一个回调函数。
它会去做(在某个地方),一旦完成,它就会调用我们的回调函数,并通过参数把工作结果或者错误信息传给我们。 它会去做(在某个地方),一旦完成,它就会调用我们的回调函数,并通过参数把工作结果或者错误信息传给我们。
.l-sub-section .l-sub-section
:marked :marked
We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web. We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web.
这里只是粗浅的说说要了解更多ES2015 Promise的信息请参见[这里](http://exploringjs.com/es6/ch_promises.html)或在Web上搜索其它学习资源。 这里只是粗浅的说说,要了解更多 ES2015 Promise 的信息,见[这里](http://exploringjs.com/es6/ch_promises.html)或在 Web 上搜索其它学习资源。
:marked :marked
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method: Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
@ -549,7 +557,7 @@ a#child-component
We pass our callback function as an argument to the !{_Promise}'s **then** method: We pass our callback function as an argument to the !{_Promise}'s **then** method:
我们把回调函数作为参数传给承诺对象的**then**函数 我们把回调函数作为参数传给承诺对象的**then**方法
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".") +makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".")
@ -558,13 +566,13 @@ a#child-component
The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
in the callback is more succinct than the equivalent function expression and gracefully handles *this*. in the callback is more succinct than the equivalent function expression and gracefully handles *this*.
回调中所用的[ES2015箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 回调中所用的 [ES2015 箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
比等价的函数表达式更加简洁,能优雅的处理*this*指针。 比等价的函数表达式更加简洁,能优雅的处理 *this* 指针。
:marked :marked
Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it! Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it!
在回调函数中,我们把服务返回的英雄数组赋值给组件的`heroes`属性。是的,这就搞定了。 在回调函数中,我们把服务返回的英雄数组赋值给组件的`heroes`属性。是的,这就搞定了。
Our app should still be running, still showing a list of heroes, and still Our app should still be running, still showing a list of heroes, and still
responding to a name selection with a detail view. responding to a name selection with a detail view.
@ -575,7 +583,7 @@ a#child-component
:marked :marked
Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection. Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection.
查看附件中的“[慢一点](#slow)”一节,来了解在较差的网络连接中这个应用会是什么样的。 查看附录中的“[慢一点](#slow)”,来了解在较差的网络连接中这个应用会是什么样的。
:marked :marked
### Review the App Structure ### Review the App Structure
@ -584,7 +592,7 @@ a#child-component
Lets verify that we have the following structure after all of our good refactoring in this chapter: Lets verify that we have the following structure after all of our good refactoring in this chapter:
再检查下,经历了本章的所有重构之后,我们应该有了下列文件结构: 再检查下,经历了本章的所有重构之后,应该有了下列文件结构:
.filetree .filetree
.file angular-tour-of-heroes .file angular-tour-of-heroes
@ -607,7 +615,7 @@ a#child-component
:marked :marked
Here are the code files we discussed in this chapter. Here are the code files we discussed in this chapter.
这就是我们在本章讨论过的这些源码文件: 下面是本章讨论过的代码文件:
+makeTabs(` +makeTabs(`
toh-4/ts/app/hero.service.ts, toh-4/ts/app/hero.service.ts,
@ -625,27 +633,27 @@ a#child-component
Lets take stock of what weve built. Lets take stock of what weve built.
来盘点一下我们已经构建完的部分 来盘点一下我们完成了什么
* We created a service class that can be shared by many components. * We created a service class that can be shared by many components.
* 我们创建了一个能被多个组件共享的服务类。 我们创建了一个能被多个组件共享的服务类。
* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates. * We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates.
* 我们使用`ngOnInit`生命周期钩子,以便在`AppComponent`激活时获取英雄数据。 我们使用了`ngOnInit`生命周期钩子,以便在`AppComponent`激活时获取英雄数据。
* We defined our `HeroService` as a provider for our `AppComponent`. * We defined our `HeroService` as a provider for our `AppComponent`.
* 我们把`HeroService`定义为`AppComponent`的一个提供商。 我们把`HeroService`定义为`AppComponent`的一个提供商。
* We created mock hero data and imported them into our service. * We created mock hero data and imported them into our service.
* 我们创建了一个模拟的英雄数据,并把它导入我们的服务中。 我们创建了模拟的英雄数据,并把它导入我们的服务中。
* We designed our service to return a !{_Promise} and our component to get our data from the !{_Promise}. * We designed our service to return a !{_Promise} and our component to get our data from the !{_Promise}.
* 我们把服务设计为返回承诺,组件从承诺中获取数据。 我们把服务设计为返回承诺,组件从承诺中获取数据。
Run the <live-example></live-example> for this part. Run the <live-example></live-example> for this part.
@ -665,7 +673,7 @@ a#child-component
We learn about Angular Component Router and navigation among the views in the [next tutorial](toh-pt5.html) chapter. We learn about Angular Component Router and navigation among the views in the [next tutorial](toh-pt5.html) chapter.
我们将在[下一章](toh-pt5.html)学习Angular组件路由以及在视图间导航的知识。 我们将在[下一章](toh-pt5.html)学习 Angular 组件路由,以及在视图间导航的知识。
.l-main-section .l-main-section
<a id="slow"></a> <a id="slow"></a>
@ -694,4 +702,4 @@ a#child-component
Back in the `AppComponent`, replace `heroService.getHeroes` with `heroService.getHeroesSlowly` Back in the `AppComponent`, replace `heroService.getHeroes` with `heroService.getHeroesSlowly`
and see how the app behaves. and see how the app behaves.
回到`AppComponent`,用`heroService.getHeroesSlowly`替换`heroService.getHeroes`,并观察应用的行为。 回到`AppComponent`,用`heroService.getHeroesSlowly`替换`heroService.getHeroes`,并观察应用的行为。