修订完toh6

This commit is contained in:
Zhicheng Wang 2017-04-16 18:22:16 +08:00
parent b7b93abd71
commit 409e17fab4
1 changed files with 31 additions and 26 deletions

View File

@ -137,9 +137,11 @@ h1 提供 HTTP 服务
that primes the in-memory database. that primes the in-memory database.
Add the file `in-memory-data.service.ts` in `app` with the following content: Add the file `in-memory-data.service.ts` in `app` with the following content:
`forRoot`配置方法需要`InMemoryDataService`类实例,用来向内存数据库填充数据: `forRoot()`配置方法需要`InMemoryDataService`类实例,用来向内存数据库填充数据:
往`app`目录下新增一个文件`in-memory-data.service.ts`,填写下列内容:
+makeExample('toh-6/ts/src/app/in-memory-data.service.ts', 'init', 'src/app/in-memory-data.service.ts')(format='.') +makeExample('toh-6/ts/src/app/in-memory-data.service.ts', 'init', 'src/app/in-memory-data.service.ts')(format='.')
:marked :marked
This file replaces `mock-heroes.ts`, which is now safe to delete. This file replaces `mock-heroes.ts`, which is now safe to delete.
@ -218,14 +220,17 @@ h1 提供 HTTP 服务
:marked :marked
The Angular `Observable` doesn't have a `toPromise` operator out of the box. The Angular `Observable` doesn't have a `toPromise` operator out of the box.
不幸的是Angular 的`Observable`并没有一个`toPromise`操作符... 没有打包在一起发布。 不幸的是Angular 的`Observable`并没有一个`toPromise`操作符... 没有打包在一起发布。Angular的`Observable`只是一个骨架实现。
Angular的`Observable`只是一个骨架实现。There are many operators like `toPromise` that extend `Observable` with useful capabilities.
To use those capabilities, you have to add the operators themselves. There are many operators like `toPromise` that extend `Observable` with useful capabilities.
That's as easy as importing them from the RxJS library like this: To use those capabilities, you have to add the operators themselves.
That's as easy as importing them from the RxJS library like this:
有很多像`toPromise`这样的操作符,用于扩展`Observable`,为其添加有用的能力。 有很多像`toPromise`这样的操作符,用于扩展`Observable`,为其添加有用的能力。
如果我们希望得到那些能力,就得自己添加那些操作符。 如果我们希望得到那些能力,就得自己添加那些操作符。
那很容易,只要从 RxJS 库中导入它们就可以了,就像这样:+makeExample('toh-6/ts/src/app/hero.service.ts', 'rxjs', '') 那很容易,只要从 RxJS 库中导入它们就可以了,就像这样:
+makeExample('toh-6/ts/src/app/hero.service.ts', 'rxjs', '')
.l-sub-section .l-sub-section
:marked :marked
@ -241,7 +246,7 @@ h1 提供 HTTP 服务
In the *Promise*'s `then()` callback , you call the `json` method of the HTTP `Response` to extract the In the *Promise*'s `then()` callback , you call the `json` method of the HTTP `Response` to extract the
data within the response. data within the response.
在 *promise* 的`then`回调中,我们调用 HTTP 的`Reponse`对象的`json`方法,以提取出其中的数据。 在 *promise* 的`then()`回调中,我们调用 HTTP 的`Reponse`对象的`json`方法,以提取出其中的数据。
+makeExample('toh-6/ts/src/app/hero.service.ts', 'to-data', '') +makeExample('toh-6/ts/src/app/hero.service.ts', 'to-data', '')
@ -296,7 +301,7 @@ h1 提供 HTTP 服务
This demo service logs the error to the console; in real life, This demo service logs the error to the console; in real life,
you would handle the error in code. For a demo, this works. you would handle the error in code. For a demo, this works.
在这个范例服务中,我们把错误记录到控制台中;在真实世界中,我们应该做得更好 在这个范例服务中,我们把错误记录到控制台中;在真实世界中,我们应该用代码对错误进行处理。但对于演示来说,这就够了
The code also includes an error to The code also includes an error to
the caller in a rejected promise, so that the caller can display a proper error message to the user. the caller in a rejected promise, so that the caller can display a proper error message to the user.
@ -375,7 +380,7 @@ h1 提供 HTTP 服务
Add the following `save()` method, which persists hero name changes using the hero service Add the following `save()` method, which persists hero name changes using the hero service
`update()` method and then navigates back to the previous view. `update()` method and then navigates back to the previous view.
`save`方法使用 hero 服务的`update`方法来持久化对英雄名字的修改,然后导航回前一个视图: `save()`方法使用 hero 服务的`update()`方法来持久化对英雄名字的修改,然后导航回前一个视图:
+makeExample('toh-6/ts/src/app/hero-detail.component.ts', 'save', 'src/app/hero-detail.component.ts (save)') +makeExample('toh-6/ts/src/app/hero-detail.component.ts', 'save', 'src/app/hero-detail.component.ts (save)')
@ -387,7 +392,7 @@ h1 提供 HTTP 服务
The overall structure of the `update()` method is similar to that of The overall structure of the `update()` method is similar to that of
`getHeroes()`, but it uses an HTTP `put()` to persist server-side changes. `getHeroes()`, but it uses an HTTP `put()` to persist server-side changes.
`update`方法的大致结构与`getHeroes`类似,不过我们使用 HTTP 的 *put* 方法来把修改持久化到服务端: `update()`方法的大致结构与`getHeroes()`类似,不过我们使用 HTTP 的 `put()` 方法来把修改持久化到服务端:
+makeExample('toh-6/ts/src/app/hero.service.ts', 'update', 'src/app/hero.service.ts (update)') +makeExample('toh-6/ts/src/app/hero.service.ts', 'update', 'src/app/hero.service.ts (update)')
@ -397,7 +402,7 @@ h1 提供 HTTP 服务
calling `JSON.stringify`. The body content type calling `JSON.stringify`. The body content type
(`application/json`) is identified in the request header. (`application/json`) is identified in the request header.
我们通过一个编码在 URL 中的英雄 id 来告诉服务器应该更新哪个英雄。put 的 body 是该英雄的 JSON 字符串,它是通过调用`JSON.stringify`得到的。 我们通过一个编码在 URL 中的英雄 `id` 来告诉服务器应该更新哪个英雄。`put` 的 body 是该英雄的 JSON 字符串,它是通过调用`JSON.stringify`得到的。
并且在请求头中标记出的 body 的内容类型(`application/json`)。 并且在请求头中标记出的 body 的内容类型(`application/json`)。
Refresh the browser, change a hero name, save your change, Refresh the browser, change a hero name, save your change,
@ -414,7 +419,7 @@ h1 提供 HTTP 服务
To add a hero, the app needs the hero's name. You can use an `input` To add a hero, the app needs the hero's name. You can use an `input`
element paired with an add button. element paired with an add button.
要添加一个新的英雄,我们得先知道英雄的名字。我们使用一个 input 元素和一个添加按钮来实现。 要添加一个新的英雄,我们得先知道英雄的名字。我们使用一个 `input` 元素和一个添加按钮来实现。
Insert the following into the heroes component HTML, just after Insert the following into the heroes component HTML, just after
the heading: the heading:
@ -479,12 +484,12 @@ h1 提供 HTTP 服务
don't want the `<li>` click handler to be triggered because doing so would don't want the `<li>` click handler to be triggered because doing so would
select the hero that the user will delete. select the hero that the user will delete.
除了调用组件的`delete`方法之外,这个`delete`按钮的点击处理器还应该阻止点击事件向上冒泡 &mdash; 除了调用组件的`delete()`方法之外,这个删除按钮的点击处理器还应该阻止点击事件向上冒泡 &mdash;
我们并不希望触发`<li>`的事件处理器,否则它会选中我们要删除的这位英雄。 我们并不希望触发`<li>`的事件处理器,否则它会选中我们要删除的这位英雄。
The logic of the `delete()` handler is a bit trickier: The logic of the `delete()` handler is a bit trickier:
`delete`处理器的逻辑略复杂: `delete()`处理器的逻辑略复杂:
+makeExample('toh-6/ts/src/app/heroes.component.ts', 'delete', 'src/app/heroes.component.ts (delete)') +makeExample('toh-6/ts/src/app/heroes.component.ts', 'delete', 'src/app/heroes.component.ts (delete)')
@ -508,7 +513,7 @@ h1 提供 HTTP 服务
:marked :marked
### Hero service _delete()_ method ### Hero service _delete()_ method
### hero 服务的`delete`方法 ### hero 服务的`delete()`方法
Add the hero service's `delete()` method, which uses the `delete()` HTTP method to remove the hero from the server: Add the hero service's `delete()` method, which uses the `delete()` HTTP method to remove the hero from the server:
@ -557,14 +562,14 @@ h1 提供 HTTP 服务
Recall that the `HeroService` chained the `toPromise` operator to the `Observable` result of `http.get()`. Recall that the `HeroService` chained the `toPromise` operator to the `Observable` result of `http.get()`.
That operator converted the `Observable` into a `Promise` and you passed that promise back to the caller. That operator converted the `Observable` into a `Promise` and you passed that promise back to the caller.
快速回忆一下`HeroService`,它在`http.get`返回的`Observable`后面串联了一个`toPromise`操作符。 快速回忆一下`HeroService`,它在`http.get()`返回的`Observable`后面串联了一个`toPromise`操作符。
该操作符把`Observable`转换成了`Promise`,并且我们把那个承诺返回给了调用者。 该操作符把`Observable`转换成了`Promise`,并且我们把那个承诺返回给了调用者。
Converting to a Promise is often a good choice. You typically ask `http.get()` to fetch a single chunk of data. Converting to a Promise is often a good choice. You typically ask `http.get()` to fetch a single chunk of data.
When you receive the data, you're done. When you receive the data, you're done.
The calling component can easily consume a single result in the form of a Promise. The calling component can easily consume a single result in the form of a Promise.
转换成承诺通常是更好地选择,我们通常会要求`http.get`获取单块数据。只要接收到数据,就算完成。 转换成承诺通常是更好地选择,我们通常会要求`http.get()`获取单块数据。只要接收到数据,就算完成。
使用承诺这种形式的结果是让调用方更容易写,并且承诺已经在 JavaScript 程序员中被广泛接受了。 使用承诺这种形式的结果是让调用方更容易写,并且承诺已经在 JavaScript 程序员中被广泛接受了。
:marked :marked
@ -608,7 +613,7 @@ h1 提供 HTTP 服务
after chaining it to another RxJS operator, <code>map()</code>, after chaining it to another RxJS operator, <code>map()</code>,
to extract heroes from the response data. to extract heroes from the response data.
RxJS operator chaining makes response processing easy and readable. RxJS operator chaining makes response processing easy and readable.
See the [discussion below about operators](#rxjs-imports).</span> See the [discussion below about operators](#rxjs-imports).
更重要的是,你不在需要调用`toPromise()`了,而是直接从`http.get()`返回一个`Observable`然后再给它串上其它的RxJS操作符如`map()`,以从响应数据中提取出英雄列表。 更重要的是,你不在需要调用`toPromise()`了,而是直接从`http.get()`返回一个`Observable`然后再给它串上其它的RxJS操作符如`map()`,以从响应数据中提取出英雄列表。
串联RxJS操作符可以让响应过程更加容易可读性也更好。 串联RxJS操作符可以让响应过程更加容易可读性也更好。
@ -636,7 +641,7 @@ h1 提供 HTTP 服务
As the user types in the search box, a *keyup* event binding calls the component's `search()` As the user types in the search box, a *keyup* event binding calls the component's `search()`
method with the new search box value. method with the new search box value.
当用户在搜索框中输入时,一个 *keyup* 事件绑定会调用该组件的`search`方法,并传入新的搜索框的值。 当用户在搜索框中输入时,一个 *keyup* 事件绑定会调用该组件的`search()`方法,并传入新的搜索框的值。
As expected, the `*ngFor` repeats hero objects from the component's `heroes` property. As expected, the `*ngFor` repeats hero objects from the component's `heroes` property.
@ -674,7 +679,7 @@ h1 提供 HTTP 服务
`Subject`主题是一个_可观察的_事件流中的生产者。 `Subject`主题是一个_可观察的_事件流中的生产者。
`searchTerms`生成一个产生字符串的`Observable`用作按名称搜索时的过滤条件。Each call to `search()` puts a new string into this subject's _observable_ stream by calling `next()`. `searchTerms`生成一个产生字符串的`Observable`用作按名称搜索时的过滤条件。Each call to `search()` puts a new string into this subject's _observable_ stream by calling `next()`.
每当调用`search`时都会调用`next`来把新的字符串放进该主题的_可观察_流中。 每当调用`search()`时都会调用`next()`来把新的字符串放进该主题的_可观察_流中。
a#ngoninit a#ngoninit
:marked :marked
@ -719,7 +724,7 @@ a#ngoninit
* `switchMap()` calls the search service for each search term that makes it through `debounce` and `distinctUntilChanged`. * `switchMap()` calls the search service for each search term that makes it through `debounce` and `distinctUntilChanged`.
It cancels and discards previous search observables, returning only the latest search service observable. It cancels and discards previous search observables, returning only the latest search service observable.
`switchMap`会为每个从`debounce`和`distinctUntilChanged`中通过的搜索词调用搜索服务。 `switchMap()`会为每个从`debounce`和`distinctUntilChanged`中通过的搜索词调用搜索服务。
它会取消并丢弃以前的搜索可观察对象,只保留最近的。 它会取消并丢弃以前的搜索可观察对象,只保留最近的。
.l-sub-section .l-sub-section
@ -732,7 +737,7 @@ a#ngoninit
借助[switchMap操作符](http://www.learnrxjs.io/operators/transformation/switchmap.html) 借助[switchMap操作符](http://www.learnrxjs.io/operators/transformation/switchmap.html)
(正式名称是`flatMapLatest`) (正式名称是`flatMapLatest`)
每次符合条件的按键事件都会触发一次对`http`方法的调用。即使在发送每个请求前都有 300 毫秒的延迟, 每次符合条件的按键事件都会触发一次对`http()`方法的调用。即使在发送每个请求前都有 300 毫秒的延迟,
我们仍然可能同时拥有多个在途的 HTTP 请求,并且它们返回的顺序未必就是发送时的顺序。 我们仍然可能同时拥有多个在途的 HTTP 请求,并且它们返回的顺序未必就是发送时的顺序。
`switchMap()` preserves the original request order while returning `switchMap()` preserves the original request order while returning
@ -751,7 +756,7 @@ a#ngoninit
doesn't actually abort a pending HTTP request. doesn't actually abort a pending HTTP request.
For now , unwanted resultsare discarded. For now , unwanted resultsare discarded.
注意,_取消_`HeroSearchService`的可观察对象并不会实际中止 (abort) 一个未完成的 HTTP 请求, 注意,*取消*`HeroSearchService`的可观察对象并不会实际中止 (abort) 一个未完成的 HTTP 请求,
除非服务支持这个特性,这个问题我们以后再讨论。 除非服务支持这个特性,这个问题我们以后再讨论。
目前我们的做法只是丢弃不希望的结果。 目前我们的做法只是丢弃不希望的结果。
@ -881,7 +886,7 @@ figure.image-display
* You extended `HeroService` to support `post()`, `put()`, and `delete()` methods. * You extended `HeroService` to support `post()`, `put()`, and `delete()` methods.
我们扩展了`HeroService`来支持 post、put 和 delete 方法。 我们扩展了`HeroService`来支持 `post()``put()``delete()` 方法。
* You updated the components to allow adding, editing, and deleting of heroes. * You updated the components to allow adding, editing, and deleting of heroes.