Merge pull request #167 from todoubaba/toh-pt6

Polish toh-pt6.jade (round 2)
This commit is contained in:
Rex 2016-12-02 14:22:25 +00:00 committed by GitHub
commit 9161d9c57e
1 changed files with 97 additions and 86 deletions

View File

@ -21,11 +21,11 @@ block includes
In this chapter we teach our application to make the corresponding HTTP calls to a remote server's web API.
在这一章中,我们要让应用程序学会通过HTTP调用来访问远程服务器上相应的Web API。
在这一章中,我们要让应用程序通过 HTTP 调用来访问远程服务器上相应的 Web API。
Run the <live-example></live-example> for this part.
p 运行这部分的<live-example>在线例子</live-example>。
运行这部分的<live-example>在线例子</live-example>。
.l-main-section
:marked
@ -47,7 +47,7 @@ block start-server-and-watch
Open a terminal/console window and enter the following command to
start the TypeScript compiler, start the server, and watch for changes:
打开terminal/console窗口输入下列命令来启动TypeScript编译器,它会启动开发服务器,并监视文件变更:
打开终端/控制台窗口,输入下列命令来启动 TypeScript 编译器,它会启动开发服务器,并监视文件变更:
code-example(language="bash").
npm start
@ -113,7 +113,6 @@ block http-providers
registering in `main` for a special reason.</span>
我们建议在根模块`!{_AppModuleVsAppComp}`的`providers`数组中注册全应用级的服务。
<span if-docs="dart">Here we're registering in `main` for a special reason.</span>
Our application is in the early stages of development and far from ready for production.
We don't even have a web server that can handle requests for heroes.
@ -128,10 +127,7 @@ block http-providers
shouldn't know about this. So we'll slip the in-memory web API into the
configuration *above* the `AppComponent`.</span>
我们要*耍点小花招*让http客户端从一个Mock服务*内存(in-memory)Web API*)中获取和保存数据。
<span if-docs="dart"> The application itself doesn't need to know and
shouldn't know about this. So we'll slip the in-memory web API into the
configuration *above* the `AppComponent`.</span>
我们要*耍点小花招*,让 HTTP 客户端从一个模拟服务(*内存 Web API*)中获取和保存数据。
Here is a version of <span ngio-ex>!{_appModuleTsVsMainTs}</span> that performs this trick:
@ -147,7 +143,9 @@ block backend
with an _in-memory web API alternative service_.
导入`InMemoryWebApiModule`并将其加入到模块的`imports`数组。
`InMemoryWebApiModule`将`Http`客户端默认的后端服务(这是一个辅助服务,负责与远程服务器对话)替换成了*内存Web API*服务:
`InMemoryWebApiModule`将`Http`客户端默认的后端服务 &mdash;
这是一个辅助服务,负责与远程服务器对话 &mdash;
替换成了*内存 Web API*服务:
+makeExcerpt(_appModuleTsVsMainTs, 'in-mem-web-api', '')
@ -169,15 +167,16 @@ block dont-be-distracted-by-backend-subst
This chapter is an introduction to the !{_Angular_http_library}.
Please don't be distracted by the details of this backend substitution. Just follow along with the example.
本章主要是介绍Angular的HTTP库不要因为这种“替换后端”的细节而分心。先不要管为什么只管照着这个例子做就可以了。
本章主要是介绍 Angular 的 HTTP 库,不要因为这种“替换后端”的细节而分心。
先不要管为什么,只管照着这个例子做就可以了。
Learn more later about the in-memory web API in the [HTTP client chapter](../guide/server-communication.html#in-mem-web-api).
Remember, the in-memory web API is only useful in the early stages of development and for demonstrations such as this Tour of Heroes.
Skip it when you have a real web API server.
要学习关于*内存Web API*的更多知识,请参阅[HTTP客户端](../guide/server-communication.html#in-mem-web-api)一章
关于*内存 Web API* 的更多信息,见 [HTTP 客户端](../guide/server-communication.html#in-mem-web-api)。
记住,*内存 Web API* 主要用于开发的早期阶段或《英雄指南》这样的演示程序。
如果你已经有了一个真实的Web API服务器尽管跳过它。
如果你已经有了一个真实的 Web API 服务器,尽管跳过它。
.l-main-section
:marked
@ -196,8 +195,9 @@ block dont-be-distracted-by-backend-subst
It may have seemed like overkill at the time, but we were anticipating the
day when we fetched heroes with an HTTP client and we knew that would have to be an asynchronous operation.
我们返回一个承诺Promise)它用mock版的英雄列表进行解析。
它当时可能看起来显得有点过于复杂不过我们早就预料到总有这么一天会通过一个HTTP客户端来获取英雄数据而且我们知道那一定是一个异步操作。
我们返回一个承诺 (Promise),它用模拟版的英雄列表进行解析。
它当时可能看起来显得有点过于复杂,不过我们预料到总有这么一天会通过 HTTP 客户端来获取英雄数据,
而且我们知道,那一定是一个异步操作。
That day has arrived! Let's convert `getHeroes()` to use HTTP.
@ -217,7 +217,7 @@ block dont-be-distracted-by-backend-subst
Refresh the browser, and the hero data should be successfully loaded from the
mock server.
刷新浏览器后,英雄数据就会从Mock服务器被成功读取。
刷新浏览器后,英雄数据就会从模拟服务器被成功读取。
<h3 id="!{_h3id}">HTTP !{_Promise}</h3>
@ -234,7 +234,7 @@ block get-heroes-details
We'll learn about [Observables](#observables) later in this chapter.
Angular 的`http.get`返回一个 RxJS 的`Observable`对象。
*Observable(可观察对象)*是一个管理异步数据流的强力方式。
*Observable(可观察对象)*是一个管理异步数据流的强力方式。
后面我们还会进一步学习[可观察对象](#observables)。
For *now* we get back on familiar ground by immediately
@ -319,7 +319,7 @@ block get-heroes-details
We must anticipate HTTP failures as they happen frequently for reasons beyond our control.
这是一个关键的步骤!
我们必须预料到http请求会失败,因为有太多我们无法控制的原因可能导致它们频繁出现各种错误。
我们必须预料到 HTTP 请求会失败,因为有太多我们无法控制的原因可能导致它们频繁出现各种错误。
+makeExcerpt('app/hero.service.ts', 'handleError', '')
@ -332,7 +332,8 @@ block get-heroes-details
We've also decided to return a user friendly form of the error to
the caller in a !{rejected_promise} so that the caller can display a proper error message to the user.
我们还要通过一个被拒绝(rejected)的承诺(promise)来把该错误用一个用户友好的格式返回给调用者,以便调用者能把一个合适的错误信息显示给用户。
我们还要通过一个被拒绝 (rejected) 的承诺来把该错误用一个用户友好的格式返回给调用者,
以便调用者能把一个合适的错误信息显示给用户。
### Unchanged `getHeroes` API
@ -376,7 +377,7 @@ block get-heroes-details
the server.
以前是不会丢失更新的,现在是怎么回事?
当该应用使用mock出来的英雄列表时,修改的是一份全局共享的英雄列表,而现在改成了从服务器获取数据。
当该应用使用模拟出来的英雄列表时,修改的是一份全局共享的英雄列表,而现在改成了从服务器获取数据。
如果我们希望这些更改被持久化,我们就得把它们写回服务器。
:marked
@ -448,7 +449,7 @@ block get-heroes-details
In response to a click event, we call the component's click handler and then
clear the input field so that it will be ready to use for another name.
click事件触发时我们调用组件的click处理器,然后清空这个输入框,以便用来输入另一个名字。
点击事件触发时,我们调用组件的点击处理器,然后清空这个输入框,以便用来输入另一个名字。
+makeExcerpt('app/heroes.component.ts', 'add')
@ -456,7 +457,8 @@ block get-heroes-details
When the given name is non-blank, the handler delegates creation of the
named hero to the hero service, and then adds the new hero to our !{_array}.
当指定的名字不为空的时候click处理器就会委托hero服务来创建一个具有此名字的英雄并把这个新的英雄添加到我们的数组中。
当指定的名字不为空的时候,点击处理器就会委托 hero 服务来创建一个具有此名字的英雄,
并把这个新的英雄添加到我们的数组中。
Finally, we implement the `create` method in the `HeroService` class.
@ -484,7 +486,7 @@ block get-heroes-details
Add this button element to the heroes component HTML, right after the hero
name in the repeated `<li>` tag:
把这个button元素添加到英雄列表组件的HTML中,把它放在`<li>`标签中的英雄名的后面:
把这个按钮元素添加到英雄列表组件的 HTML 中,把它放在`<li>`标签中的英雄名的后面:
+makeExcerpt('app/heroes.component.html', 'delete', '')
@ -501,7 +503,8 @@ block get-heroes-details
don't want the `<li>` click handler to be triggered because that would
select the hero that we are going to delete!
除了调用组件的`delete`方法之外,这个`delete`按钮的click处理器还应该阻止click事件向上冒泡 —— 我们并不希望触发`<li>`的事件处理器,否则它会选中我们要删除的这位英雄。
除了调用组件的`delete`方法之外,这个`delete`按钮的点击处理器还应该阻止点击事件向上冒泡 &mdash;
我们并不希望触发`<li>`的事件处理器,否则它会选中我们要删除的这位英雄。
The logic of the `delete` handler is a bit trickier:
@ -514,7 +517,8 @@ block get-heroes-details
is still responsible for updating the display: it removes the deleted hero
from the !{_array} and resets the selected hero if necessary.
当然我们仍然把删除英雄的操作委托给了hero服务不过该组件仍然负责更新显示它从数组中移除了被删除的英雄如果删除的是正选中的英雄还会清空选择。
当然,我们仍然把删除英雄的操作委托给了 hero 服务,
不过该组件仍然负责更新显示:它从数组中移除了被删除的英雄,如果删除的是正选中的英雄,还会清空选择。
:marked
We want our delete button to be placed at the far right of the hero entry.
@ -545,7 +549,7 @@ block get-heroes-details
:marked
## !{_Observable}s
## 可观察对象Observable
## 可观察对象 (Observable)
block observables-section-intro
:marked
@ -566,7 +570,7 @@ block observables-section-intro
An *observable* is a stream of events that we can process with array-like operators.
一个*可观察对象*是一个事件流,我们可以用数组型操作符(函数)来处理它。
一个*可观察对象*是一个事件流,我们可以用数组型操作符来处理它。
Angular core has basic support for observables. We developers augment that support with
operators and extensions from the [RxJS Observables](http://reactivex.io/rxjs/) library.
@ -595,7 +599,8 @@ block observables-section-intro
Such a _request-cancel-new-request_ sequence is difficult to implement with *!{_Promise}s*.
It's easy with *!{_Observable}s* as we'll see.
但是请求并非总是“一次性”的。我们可以开始一个请求,并且取消它,再开始另一个不同的请求 —— 在服务器对第一个请求作出回应之前。
但是请求并非总是“一次性”的。我们可以开始一个请求,
并且取消它,在服务器对第一个请求作出回应之前,再开始另一个不同的请求 。
像这样一个_请求-取消-新请求_的序列用*承诺*是很难实现的,但接下来我们会看到,它对于*可观察对象*却很简单。
### Search-by-name
@ -723,17 +728,20 @@ block observable-transformers
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
before passing along the latest string. We'll never make requests more frequently than 300ms.
* 在传出最终字符串之前,`debounceTime(300)`将会等待直到新增字符串的事件暂停了300毫秒。我们实际发起请求的间隔永远不会小于300ms。
在传出最终字符串之前,`debounceTime(300)`将会等待,直到新增字符串的事件暂停了 300 毫秒。
我们实际发起请求的间隔永远不会小于 300ms。
* `distinctUntilChanged` ensures that we only send a request if the filter text changed.
There's no point in repeating a request for the same search term.
* `distinctUntilChanged`确保只在过滤条件变化时才发送请求,这样就不会重复请求同一个搜索词了。
`distinctUntilChanged`确保只在过滤条件变化时才发送请求,
这样就不会重复请求同一个搜索词了。
* `switchMap` calls our search service for each search term that makes it through the `debounce` and `distinctUntilChanged` gauntlet.
It cancels and discards previous search observables, returning only the latest search service observable.
* `switchMap`会为每个从`debounce`和`distinctUntilChanged`中通过的搜索词调用搜索服务。它会取消并丢弃以前的搜索可观察对象,只保留最近的。
`switchMap`会为每个从`debounce`和`distinctUntilChanged`中通过的搜索词调用搜索服务。
它会取消并丢弃以前的搜索可观察对象,只保留最近的。
.l-sub-section
:marked
@ -747,13 +755,14 @@ block observable-transformers
Even with a 300ms pause between requests, we could have multiple HTTP requests in flight
and they may not return in the order sent.
每次符合条件的按键事件都会触发一次对`http`方法的调用。即使在发送每个请求前都有300毫秒的延迟我们仍然可能同时拥有多个在途的HTTP请求并且它们返回的顺序未必就是发送时的顺序。
每次符合条件的按键事件都会触发一次对`http`方法的调用。即使在发送每个请求前都有 300 毫秒的延迟,
我们仍然可能同时拥有多个在途的 HTTP 请求,并且它们返回的顺序未必就是发送时的顺序。
`switchMap` preserves the original request order while returning
only the observable from the most recent `http` method call.
Results from prior calls are canceled and discarded.
`switchMap`保留了原始的请求顺序并且只返回最近一次http调用返回的可观察对象。
`switchMap`保留了原始的请求顺序,并且只返回最近一次 `http` 调用返回的可观察对象。
这是因为以前的调用都被取消或丢弃了。
We also short-circuit the `http` method call and return an observable containing an empty array
@ -765,7 +774,8 @@ block observable-transformers
until the service supports that feature, a topic for another day.
We are content for now to discard unwanted results.
注意_取消_`HeroSearchService`的可观察对象并不会实际中止abort一个未完成的HTTP请求除非服务支持这个特性这个问题我们以后再讨论。
注意_取消_`HeroSearchService`的可观察对象并不会实际中止 (abort) 一个未完成的 HTTP 请求,
除非服务支持这个特性,这个问题我们以后再讨论。
目前我们的做法只是丢弃不希望的结果。
:marked
@ -788,7 +798,8 @@ block observable-transformers
We could extend `Observable` with just the operators we need here by
including the pertinent `import` statements at the top of this file.
通过在本文件的顶部写上适当的`import`语句,我们可以为`Observable`扩展出这里用到的那些操作符。
通过在本文件的顶部写上适当的`import`语句,
我们可以为`Observable`扩展出这里用到的那些操作符。
.l-sub-section
:marked
@ -903,27 +914,27 @@ block filetree
- We added the necessary dependencies to use HTTP in our application.
- 我们添加了在应用程序中使用HTTP的必备依赖。
我们添加了在应用程序中使用 HTTP 的必备依赖。
- We refactored `HeroService` to load heroes from a web API.
- 我们重构了`HeroService`以通过web API来加载英雄数据。
我们重构了`HeroService`,以通过 web API 来加载英雄数据。
- We extended `HeroService` to support post, put and delete methods.
- 我们扩展了`HeroService`来支持post、put和delete方法。
我们扩展了`HeroService`来支持 post、put 和 delete 方法。
- We updated our components to allow adding, editing and deleting of heroes.
- 我们更新了组件,以允许用户添加、编辑和删除英雄。
我们更新了组件,以允许用户添加、编辑和删除英雄。
- We configured an in-memory web API.
- 我们配置了一个内存Web API。
我们配置了一个内存 Web API。
- We learned how to use !{_Observable}s.
- 我们学会了如何使用“可观察对象”。
我们学会了如何使用“可观察对象”。
Here are the files we _added or changed_ in this chapter.