Polish toh-pt6.jade (round 2)
This commit is contained in:
parent
2040b6ecd2
commit
4e49ba9cd0
|
@ -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
|
||||
|
@ -60,7 +60,7 @@ block start-server-and-watch
|
|||
.l-main-section#http-providers
|
||||
h1 Providing HTTP Services
|
||||
|
||||
h1 准备HTTP服务
|
||||
h1 准备 HTTP 服务
|
||||
|
||||
block http-library
|
||||
:marked
|
||||
|
@ -68,25 +68,25 @@ block http-library
|
|||
It's Angular's optional approach to web access and it exists as a separate add-on module called `@angular/http`,
|
||||
shipped in a separate script file as part of the Angular npm package.
|
||||
|
||||
`HttpModule`***并不是***Angular的核心模块。
|
||||
它是Angular用来进行Web访问的一种可选方式,并通过Angular包中一个名叫`@angular/http`的独立附属模块发布了出来。
|
||||
`HttpModule`***并不是*** Angular 的核心模块。
|
||||
它是 Angular 用来进行 Web 访问的一种可选方式,并通过 Angular 包中一个名叫`@angular/http`的独立附属模块发布了出来。
|
||||
|
||||
Fortunately we're ready to import from `@angular/http` because `systemjs.config` configured *SystemJS* to load that library when we need it.
|
||||
|
||||
幸运的是,`systemjs.config`中已经配置好了*SystemJS*,并在必要时加载它,因此我们已经为从`@angular/http`中导入它做好了准备。
|
||||
幸运的是,`systemjs.config`中已经配置好了 *SystemJS*,并在必要时加载它,因此我们已经为从`@angular/http`中导入它做好了准备。
|
||||
|
||||
:marked
|
||||
### Register for HTTP services
|
||||
|
||||
### 注册*HTTP*服务
|
||||
### 注册 *HTTP* 服务
|
||||
|
||||
block http-providers
|
||||
:marked
|
||||
Our app will depend upon the Angular `http` service which itself depends upon other supporting services.
|
||||
The `HttpModule` from `@angular/http` library holds providers for a complete set of HTTP services.
|
||||
|
||||
我们的应用将会依赖于Angular的`http`服务,它本身又依赖于其它支持类服务。
|
||||
来自`@angular/http`库中的`HttpModule`保存着这些HTTP相关服务提供商的全集。
|
||||
我们的应用将会依赖于 Angular 的`http`服务,它本身又依赖于其它支持类服务。
|
||||
来自`@angular/http`库中的`HttpModule`保存着这些 HTTP 相关服务提供商的全集。
|
||||
|
||||
We should be able to access these services from anywhere in the application.
|
||||
So we register them all by adding `HttpModule` to the `imports` list of the `AppModule` where we
|
||||
|
@ -113,14 +113,13 @@ 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.
|
||||
Until we do, *we'll have to fake it*.
|
||||
|
||||
我们的应用正处于开发的早期阶段,并且离进入产品阶段还很远。
|
||||
我们甚至都还没有一个用来处理英雄相关请求的Web服务器,在此之前,*我们将不得不伪造一个*。
|
||||
我们甚至都还没有一个用来处理英雄相关请求的 Web 服务器,在此之前,*我们将不得不伪造一个*。
|
||||
|
||||
We're going to *trick* the HTTP client into fetching and saving data from
|
||||
a mock service, the *in-memory web API*.
|
||||
|
@ -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`客户端默认的后端服务 —
|
||||
这是一个辅助服务,负责与远程服务器对话 —
|
||||
替换成了*内存 Web API*服务:
|
||||
|
||||
+makeExcerpt(_appModuleTsVsMainTs, 'in-mem-web-api', '')
|
||||
|
||||
|
@ -169,21 +167,22 @@ 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*主要用于开发的早期阶段或《英雄指南》这样的演示程序。
|
||||
如果你已经有了一个真实的Web API服务器,请尽管跳过它。
|
||||
关于*内存 Web API* 的更多信息,见 [HTTP 客户端](../guide/server-communication.html#in-mem-web-api)。
|
||||
记住,*内存 Web API* 主要用于开发的早期阶段或《英雄指南》这样的演示程序。
|
||||
如果你已经有了一个真实的 Web API 服务器,尽管跳过它。
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Heroes and HTTP
|
||||
|
||||
## 英雄与HTTP
|
||||
## 英雄与 HTTP
|
||||
|
||||
Look at our current `HeroService` implementation
|
||||
|
||||
|
@ -196,12 +195,13 @@ 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.
|
||||
|
||||
这一天到来了!我们把`getHeroes()`换成用HTTP。
|
||||
这一天到来了!我们把`getHeroes()`换成用 HTTP。
|
||||
|
||||
+makeExcerpt('app/hero.service.ts (updated getHeroes and new class members)', 'getHeroes')
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -233,8 +233,8 @@ block get-heroes-details
|
|||
*Observables* are a powerful way to manage asynchronous data flows.
|
||||
We'll learn about [Observables](#observables) later in this chapter.
|
||||
|
||||
Angular的`http.get`返回一个RxJS的`Observable`对象。
|
||||
*Observable(可观察对象)*是一个管理异步数据流的强力方式。
|
||||
Angular 的`http.get`返回一个 RxJS 的`Observable`对象。
|
||||
*Observable(可观察对象)*是一个管理异步数据流的强力方式。
|
||||
后面我们还会进一步学习[可观察对象](#observables)。
|
||||
|
||||
For *now* we get back on familiar ground by immediately
|
||||
|
@ -249,7 +249,7 @@ block get-heroes-details
|
|||
not out of the box.
|
||||
The Angular `Observable` is a bare-bones implementation.
|
||||
|
||||
不幸的是,Angular的`Observable`并没有一个`toPromise`操作符... 没有打包在一起发布。
|
||||
不幸的是,Angular 的`Observable`并没有一个`toPromise`操作符... 没有打包在一起发布。
|
||||
Angular的`Observable`只是一个骨架实现。
|
||||
|
||||
There are scores of operators like `toPromise` that extend `Observable` with useful capabilities.
|
||||
|
@ -258,19 +258,19 @@ block get-heroes-details
|
|||
|
||||
有很多像`toPromise`这样的操作符,用于扩展`Observable`,为其添加有用的能力。
|
||||
如果我们希望得到那些能力,就得自己添加那些操作符。
|
||||
那很容易,只要从RxJS库中导入它们就可以了,就像这样:
|
||||
那很容易,只要从 RxJS 库中导入它们就可以了,就像这样:
|
||||
|
||||
+makeExcerpt('app/hero.service.ts', 'rxjs', '')
|
||||
|
||||
:marked
|
||||
### Extracting the data in the *then* callback
|
||||
|
||||
### 在*then*回调中提取出数据
|
||||
### 在 *then* 回调中提取出数据
|
||||
|
||||
In the *promise*'s `then` callback we call the `json` method of the HTTP `Response` to extract the
|
||||
data within the response.
|
||||
|
||||
在*promise*的`then`回调中,我们调用HTTP的`Reponse`对象的`json`方法,以提取出其中的数据。
|
||||
在 *promise* 的`then`回调中,我们调用 HTTP 的`Reponse`对象的`json`方法,以提取出其中的数据。
|
||||
|
||||
+makeExcerpt('app/hero.service.ts', 'to-data', '')
|
||||
|
||||
|
@ -290,8 +290,8 @@ block get-heroes-details
|
|||
Your API might return something else. Adjust the code to match *your web API*.
|
||||
|
||||
仔细看看这个由服务器返回的数据的形态。
|
||||
这个*内存Web API*的范例中所做的是返回一个带有`data`属性的对象。
|
||||
你的API也可以返回其它东西。请调整这些代码以匹配*你的Web API*。
|
||||
这个*内存 Web API* 的范例中所做的是返回一个带有`data`属性的对象。
|
||||
你的 API 也可以返回其它东西。请调整这些代码以匹配*你的 Web API*。
|
||||
|
||||
:marked
|
||||
The caller is unaware of these machinations. It receives a !{_Promise} of *heroes* just as it did before.
|
||||
|
@ -301,7 +301,7 @@ block get-heroes-details
|
|||
|
||||
调用者并不知道这些实现机制,它仍然像以前那样接收一个包含*英雄数据*的承诺。
|
||||
它也不知道我们已经改成了从服务器获取英雄数据。
|
||||
它也不必了解把HTTP响应转换成英雄数据时所作的这些复杂变换。
|
||||
它也不必了解把 HTTP 响应转换成英雄数据时所作的这些复杂变换。
|
||||
看到美妙之处了吧,这正是将数据访问委托组一个服务的目的。
|
||||
|
||||
### Error Handling
|
||||
|
@ -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,11 +332,12 @@ 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
|
||||
|
||||
### `getHeroes` API没变
|
||||
### `getHeroes` API 没变
|
||||
|
||||
Although we made significant *internal* changes to `getHeroes()`, the public signature did not change.
|
||||
We still return a !{_Promise}. We won't have to update any of the components that call `getHeroes()`.
|
||||
|
@ -347,7 +348,7 @@ block get-heroes-details
|
|||
Our stakeholders are thrilled with the added flexibility from the API integration.
|
||||
Now they want the ability to create and delete heroes.
|
||||
|
||||
我们的客户很欣赏这种富有弹性的API集成方式。
|
||||
我们的客户很欣赏这种富有弹性的 API 集成方式。
|
||||
现在它们想增加创建和删除英雄的功能。
|
||||
|
||||
Let's see first what happens when we try to update a hero's details.
|
||||
|
@ -376,7 +377,7 @@ block get-heroes-details
|
|||
the server.
|
||||
|
||||
以前是不会丢失更新的,现在是怎么回事?
|
||||
当该应用使用mock出来的英雄列表时,修改的是一份全局共享的英雄列表,而现在改成了从服务器获取数据。
|
||||
当该应用使用模拟出来的英雄列表时,修改的是一份全局共享的英雄列表,而现在改成了从服务器获取数据。
|
||||
如果我们希望这些更改被持久化,我们就得把它们写回服务器。
|
||||
|
||||
:marked
|
||||
|
@ -396,20 +397,20 @@ block get-heroes-details
|
|||
The `save` method persists hero name changes using the hero service
|
||||
`update` method and then navigates back to the previous view:
|
||||
|
||||
`save`方法使用hero服务的`update`方法来持久化对英雄名字的修改,然后导航回前一个视图:
|
||||
`save`方法使用 hero 服务的`update`方法来持久化对英雄名字的修改,然后导航回前一个视图:
|
||||
|
||||
+makeExcerpt('app/hero-detail.component.ts', 'save')
|
||||
|
||||
:marked
|
||||
### Hero service `update` method
|
||||
|
||||
### hero服务的`update`方法
|
||||
### hero 服务的`update`方法
|
||||
|
||||
The overall structure of the `update` method is similar to that of
|
||||
`getHeroes`, although we'll use an HTTP _put_ to persist changes
|
||||
server-side:
|
||||
|
||||
`update`方法的大致结构与`getHeroes`类似,不过我们使用HTTP的*put*方法来把修改持久化到服务端:
|
||||
`update`方法的大致结构与`getHeroes`类似,不过我们使用 HTTP 的 *put* 方法来把修改持久化到服务端:
|
||||
|
||||
+makeExcerpt('app/hero.service.ts', 'update')
|
||||
|
||||
|
@ -419,8 +420,8 @@ block get-heroes-details
|
|||
calling `!{_JSON_stringify}`. We identify the body content type
|
||||
(`application/json`) in the request header.
|
||||
|
||||
我们通过一个编码在URL中的英雄id来告诉服务器应该更新哪个英雄。put的body是该英雄的JSON字符串,它是通过调用`!{_JSON_stringify}`得到的。
|
||||
并且在请求头中标记出的body的内容类型(`application/json`)。
|
||||
我们通过一个编码在 URL 中的英雄 id 来告诉服务器应该更新哪个英雄。put 的 body 是该英雄的 JSON 字符串,它是通过调用`!{_JSON_stringify}`得到的。
|
||||
并且在请求头中标记出的 body 的内容类型(`application/json`)。
|
||||
|
||||
Refresh the browser and give it a try. Changes to hero names should now persist.
|
||||
|
||||
|
@ -435,12 +436,12 @@ block get-heroes-details
|
|||
To add a new hero we need to know the hero's name. Let's use an input
|
||||
element for that, paired with an add button.
|
||||
|
||||
要添加一个新的英雄,我们得先知道英雄的名字。我们使用一个input元素和一个添加按钮来实现。
|
||||
要添加一个新的英雄,我们得先知道英雄的名字。我们使用一个 input 元素和一个添加按钮来实现。
|
||||
|
||||
Insert the following into the heroes component HTML, first thing after
|
||||
the heading:
|
||||
|
||||
把下列代码插入heroes组件的HTML中,放在标题的下面:
|
||||
把下列代码插入 heroes 组件的 HTML 中,放在标题的下面:
|
||||
|
||||
+makeExcerpt('app/heroes.component.html', 'add')
|
||||
|
||||
|
@ -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`按钮的点击处理器还应该阻止点击事件向上冒泡 —
|
||||
我们并不希望触发`<li>`的事件处理器,否则它会选中我们要删除的这位英雄。
|
||||
|
||||
The logic of the `delete` handler is a bit trickier:
|
||||
|
||||
|
@ -514,25 +517,26 @@ 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.
|
||||
This extra CSS accomplishes that:
|
||||
|
||||
我们希望删除按钮被放在英雄条目的最右边。
|
||||
于是CSS变成了这样:
|
||||
于是 CSS 变成了这样:
|
||||
|
||||
+makeExcerpt('app/heroes.component.css', 'additions')
|
||||
|
||||
:marked
|
||||
### Hero service `delete` method
|
||||
|
||||
### hero服务的`delete`方法
|
||||
### hero 服务的`delete`方法
|
||||
|
||||
The hero service's `delete` method uses the _delete_ HTTP method to remove the hero from the server:
|
||||
|
||||
hero服务的`delete`方法使用HTTP的*delete*方法来从服务器上移除该英雄:
|
||||
hero 服务的`delete`方法使用 HTTP 的 *delete* 方法来从服务器上移除该英雄:
|
||||
|
||||
+makeExcerpt('app/hero.service.ts', 'delete')
|
||||
|
||||
|
@ -545,13 +549,13 @@ block get-heroes-details
|
|||
:marked
|
||||
## !{_Observable}s
|
||||
|
||||
## 可观察对象(Observable)
|
||||
## 可观察对象 (Observable)
|
||||
|
||||
block observables-section-intro
|
||||
:marked
|
||||
Each `Http` service method returns an `Observable` of HTTP `Response` objects.
|
||||
|
||||
`Http`服务中的每个方法都返回一个HTTP `Response`对象的`Observable`实例。
|
||||
`Http`服务中的每个方法都返回一个 HTTP `Response`对象的`Observable`实例。
|
||||
|
||||
Our `HeroService` converts that `Observable` into a `Promise` and returns the promise to the caller.
|
||||
In this section we learn to return the `Observable` directly and discuss when and why that might be
|
||||
|
@ -566,13 +570,13 @@ 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.
|
||||
We'll see how shortly.
|
||||
|
||||
Angular内核中提供了对可观察对象的基本支持。而我们这些开发人员可以自己从[RxJS可观察对象](http://reactivex.io/rxjs/)库中引入操作符和扩展。
|
||||
Angular 内核中提供了对可观察对象的基本支持。而我们这些开发人员可以自己从 [RxJS 可观察对象](http://reactivex.io/rxjs/)库中引入操作符和扩展。
|
||||
我们会简短的讲解下如何做。
|
||||
|
||||
Recall that our `HeroService` quickly chained the `toPromise` operator to the `Observable` result of `http.get`.
|
||||
|
@ -587,7 +591,7 @@ block observables-section-intro
|
|||
and it helps that promises are widely understood by JavaScript programmers.
|
||||
|
||||
转换成承诺通常是更好地选择,我们通常会要求`http.get`获取单块数据。只要接收到数据,就算完成。
|
||||
使用承诺这种形式的结果是让调用方更容易写,并且承诺已经在JavaScript程序员中被广泛接受了。
|
||||
使用承诺这种形式的结果是让调用方更容易写,并且承诺已经在 JavaScript 程序员中被广泛接受了。
|
||||
|
||||
:marked
|
||||
But requests aren't always "one and done". We may start one request,
|
||||
|
@ -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
|
||||
|
@ -606,11 +611,11 @@ block observables-section-intro
|
|||
As the user types a name into a search box, we'll make repeated HTTP requests for heroes filtered by that name.
|
||||
|
||||
我们要为《英雄指南》添加一个*英雄搜索*特性。
|
||||
当用户在搜索框中输入一个名字时,我们将不断发起HTTP请求,以获得按名字过滤的英雄。
|
||||
当用户在搜索框中输入一个名字时,我们将不断发起 HTTP 请求,以获得按名字过滤的英雄。
|
||||
|
||||
We start by creating `HeroSearchService` that sends search queries to our server's web api.
|
||||
|
||||
我们先创建`HeroSearchService`服务,它会把搜索请求发送到我们服务器上的Web API。
|
||||
我们先创建`HeroSearchService`服务,它会把搜索请求发送到我们服务器上的 Web API。
|
||||
|
||||
+makeExample('app/hero-search.service.ts')
|
||||
|
||||
|
@ -647,11 +652,11 @@ block observables-section-intro
|
|||
:marked
|
||||
As the user types in the search box, a *keyup* event binding calls the component's `search` method with the new search box value.
|
||||
|
||||
当用户在搜索框中输入时,一个*keyup*事件绑定会调用该组件的`search`方法,并传入新的搜索框的值。
|
||||
当用户在搜索框中输入时,一个 *keyup* 事件绑定会调用该组件的`search`方法,并传入新的搜索框的值。
|
||||
|
||||
The `*ngFor` repeats *hero* objects from the component's `heroes` property. No surprise there.
|
||||
|
||||
`*ngFor`从该组件的`heroes`属性重复获取*hero*对象。这也没啥特别的。
|
||||
`*ngFor`从该组件的`heroes`属性重复获取 *hero* 对象。这也没啥特别的。
|
||||
|
||||
But, as we'll soon see, the `heroes` property is now !{_an} *!{_Observable}* of hero !{_array}s, rather than just a hero !{_array}.
|
||||
The `*ngFor` can't do anything with !{_an} `!{_Observable}` until we flow it through the `async` pipe (`AsyncPipe`).
|
||||
|
@ -694,7 +699,7 @@ block search-criteria-intro
|
|||
<a id="ngoninit"></a>
|
||||
#### Initialize the _**heroes**_ property (_**ngOnInit**_)
|
||||
|
||||
#### 初始化_**heroes**_属性(_**ngOnInit**_)
|
||||
#### 初始化 _**heroes**_ 属性(_**ngOnInit**_)
|
||||
|
||||
<span if-docs="ts">A `Subject` is also an `Observable`.</span>
|
||||
We're going to turn the stream
|
||||
|
@ -709,7 +714,7 @@ block search-criteria-intro
|
|||
If we passed every user keystroke directly to the `HeroSearchService`, we'd unleash a storm of HTTP requests.
|
||||
Bad idea. We don't want to tax our server resources and burn through our cellular network data plan.
|
||||
|
||||
如果我们直接把每一次用户按键都直接传给`HeroSearchService`,就会发起一场HTTP请求风暴。
|
||||
如果我们直接把每一次用户按键都直接传给`HeroSearchService`,就会发起一场 HTTP 请求风暴。
|
||||
这可不好玩。我们不希望占用服务器资源,也不想耗光蜂窝移动网络的流量。
|
||||
|
||||
block observable-transformers
|
||||
|
@ -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
|
||||
|
@ -777,18 +787,19 @@ block observable-transformers
|
|||
|
||||
### Import RxJS operators
|
||||
|
||||
### 导入RxJS操作符
|
||||
### 导入 RxJS 操作符
|
||||
|
||||
The RxJS operators are not available in Angular's base `Observable` implementation.
|
||||
We have to extend `Observable` by *importing* them.
|
||||
|
||||
Angular的基本版`Observable`实现中,RxJS操作符是不可用的。
|
||||
Angular 的基本版`Observable`实现中,RxJS 操作符是不可用的。
|
||||
我们得*导入*它们,以扩展`Observable`。
|
||||
|
||||
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
|
||||
|
@ -801,7 +812,7 @@ block observable-transformers
|
|||
We combine all of the RxJS `Observable` extensions that _our entire app_ requires into a single RxJS imports file.
|
||||
|
||||
在这个例子中,我们使用一些不同的方法。
|
||||
我们把整个应用中要用的那些RxJS `Observable`扩展组合在一起,放在一个单独的RxJS导入文件中。
|
||||
我们把整个应用中要用的那些 RxJS `Observable`扩展组合在一起,放在一个单独的 RxJS 导入文件中。
|
||||
|
||||
+makeExample('app/rxjs-extensions.ts')(format='.')
|
||||
|
||||
|
@ -819,7 +830,7 @@ block observable-transformers
|
|||
|
||||
We add the hero search HTML element to the bottom of the `DashboardComponent` template.
|
||||
|
||||
将表示“英雄搜索”组件的HTML元素添加到`DashboardComponent`模版的最后面。
|
||||
将表示“英雄搜索”组件的 HTML 元素添加到`DashboardComponent`模版的最后面。
|
||||
|
||||
+makeExample('app/dashboard.component.html')(format='.')
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue