anchor.diff:    But we want to *save* data too. We can't save changes to a JSON file. We need a web API server.
     We didn't want the hassle of setting up and maintaining a real server for this chapter.
     So we turned to an *in-memory web API simulator* instead.
  +  
  +  这在*“获取”英雄数据*的场景下确实能工作，但我们还想*保存*数据。我们不能把这些改动保存到JSON文件中，我们需要一个Web API服务器。
  +  在本章中，我们不想惹上配置和维护真实服务器的那些麻烦事。
  +  所以，我们转而使用一种*内存Web API仿真器*代替它。
   
   .l-sub-section
     :marked
  
positive.code:     It's an optional service in its own `angular2-in-memory-web-api` library
      that we installed with npm (see `package.json`) and 
      registered for module loading by SystemJS (see `systemjs.config.js`)
  
  :marked
    The in-memory web API gets its data from #{_a_ca_class_with} a `createDb()`
    method that returns a map whose keys are collection names and whose values 
    are #{_array}s of objects in those collections.
    
    Here's the class we created for this sample based on the JSON data:
  +makeExample('server-communication/ts/app/hero-data.ts', null, 'app/hero-data.ts')(format=".")
  :marked
    Ensure that the `HeroService` endpoint refers to the web API:
  +makeExample('server-communication/ts/app/toh/hero.service.ts', 'endpoint')(format=".")
  :marked
    Finally, we need to redirect client HTTP requests to the in-memory web API.
  block redirect-to-web-api
    :marked
      This redirection is easy to configure because Angular's `http` service delegates the client/server communication tasks
      to a helper service called the `XHRBackend`. 
  
      To enable our server simulation, we replace the default `XHRBackend` service with 
      the in-memory web API service using standard Angular provider registration techniques. 
      We initialize the in-memory web API with *seed data* from the mock hero dataset at the same time.
  
  p Here is the revised (and final) version of the #[code #[+adjExPath('app/main.ts')]] demonstrating these steps.
  +makeExample('server-communication/ts/app/main.ts', 'final', 'app/main.ts (final)')(format=".")
  
  p See the full source code in the #[+liveExampleLink2()].
  
negative.code:     Wikipedia offers a modern `CORS` API and a legacy `JSONP` search API. Let's use the latter for this example.
      The Angular `Jsonp` service both extends the `#{_Http}` service for JSONP and restricts us to `GET` requests. 
      All other HTTP methods throw an error because JSONP is a read-only facility. 
      
      Wikipedia提供了一个现代的`CORS` API和一个传统的`JSONP`搜索API。在这个例子中，我们使用后者。
      Angular的`Jsonp`服务既通过JSONP扩展了`#{_Http}`服务，又限制了我们只能用`GET`请求。
      尝试调用所有其它HTTP方法都将抛出一个错误，这是因为JSONP是只读的。
  
      As always, we wrap our interaction with an Angular data access client service inside a dedicated service, here called `WikipediaService`.
      
      像往常一样，我们把和Angular数据访问服务进行交互的代码全都封装在一个专门的服务中。我们称之为`WikipediaService`。
  
    +makeExample('server-communication/ts/app/wiki/wikipedia.service.ts',null,'app/wiki/wikipedia.service.ts')
    :marked
      The constructor expects Angular to inject its `jsonp` service. 
      We register that service with `JSONP_PROVIDERS` in the  [component below](#wikicomponent) that calls our `WikipediaService`.
      
      这个构造函数期望Angular给它注入一个`jsonp`服务。
      我们在[下面这个组件](#wikicomponent)(它会调用`WikipediaService`服务)中，用`JSONP_PROVIDERS`注册了这个服务。
  
    <a id="query-parameters"></a>
    :marked
      ### Search parameters
      ### 搜索参数
      The [Wikipedia 'opensearch' API](https://www.mediawiki.org/wiki/API:Opensearch)
      expects four parameters (key/value pairs) to arrive in the request URL's query string.
      The keys are `search`, `action`, `format`, and `callback`.
      The value of the `search` key is the user-supplied search term to find in Wikipedia.
      The other three are the fixed values "opensearch", "json", and "JSONP_CALLBACK" respectively.
      
      [Wikipedia 的 'opensearch' API](https://www.mediawiki.org/wiki/API:Opensearch)期待在所请求的URL中带四个查询参数（键/值对格式）。
      这些键(key)分别是`search`、`action`、`format`和`callback`。
      `search`的值是一个用户提供的打算在Wikipedia中查找的关键字。
      另外三个参数是固定值，分别是"opensearch"、"json"和"JSONP_CALLBACK"。
    .l-sub-section
      :marked
        The `JSONP` technique requires that we pass a callback function name to the server in the query string: `callback=JSONP_CALLBACK`.
        The server uses that name to build a JavaScript wrapper function in its response which Angular ultimately calls to extract the data.
        All of this happens under the hood.
        
        `JSONP`技术需要我们通过查询参数传给服务器一个回调函数的名字：`callback=JSONP_CALLBACK`。
        服务器使用这个名字在它的响应体中构建一个JavaScript包装函数，Angular最终会调用这个包装函数来提取出数据。
        这些都是Angular在背后默默完成的，你不会感受到它。
    :marked
      If we're looking for articles with the word "Angular", we could construct the query string by hand and call `jsonp` like this:
      
      如果我们要找那些含有关键字“Angular”的文档，我们可以先手工构造出查询字符串，并像这样调用`jsonp`：
    +makeExample('server-communication/ts/app/wiki/wikipedia.service.1.ts','query-string')(format='.')
    :marked
      In more parameterized examples we might prefer to build the query string with the Angular `URLSearchParams` helper as shown here:
      
      在更为参数化的例子中，我们会首选Angular的`URLSearchParams`辅助类来构建查询字符串，就像这样：
    +makeExample('server-communication/ts/app/wiki/wikipedia.service.ts','search-parameters','app/wiki/wikipedia.service.ts (search parameters)')(format=".")
    :marked
      This time we call `jsonp` with *two* arguments: the `wikiUrl` and an options object whose `search` property is the `params` object.
      
      这次我们使用了*两个*参数来调用`jsonp`：`wikiUrl`和一个配置对象，配置对象的`search`属性是刚构建的这个`params`对象。
    +makeExample('server-communication/ts/app/wiki/wikipedia.service.ts','call-jsonp','app/wiki/wikipedia.service.ts (call jsonp)')(format=".")
    :marked
      `Jsonp` flattens the `params` object into the same query string we saw earlier before putting the request on the wire.
      
      `Jsonp`把`params`对象平面化为一个查询字符串，而这个查询字符串和以前我们直接放在请求中的那个是一样的。
  
    <a id="wikicomponent"></a>
    :marked
      ### The WikiComponent
      ### WikiComponent组件
  
      Now that we have a service that can query the Wikipedia API, 
      we turn to the component that takes user input and displays search results.
      
      现在，我们有了一个可用于查询Wikpedia API的服务，
      我们重新回到组件中，接收用户输入，并显示搜索结果。
  
    +makeExample('server-communication/ts/app/wiki/wiki.component.ts', null, 'app/wiki/wiki.component.ts')
    :marked
      The `providers` array in the component metadata specifies the Angular `JSONP_PROVIDERS` collection that supports the `Jsonp` service.
      We register that collection at the component level to make `Jsonp` injectable in the `WikipediaService`.
      
      该组件元数据中的`providers`数组指定了Angular的`JSONP_PROVIDERS`集合，以支持`Jsonp`服务。
      我们把这个集合注册在组件级，以便`Jsonp`可以被注入进`WikipediaService`中。
  
      The component presents an `<input>` element *search box* to gather search terms from the user. 
      and calls a `search(term)` method after each `keyup` event.
      
      该组件把一个`<input>`元素作为*搜索框*作为从用户那里手机搜索关键字的入口。
      并在每次`keyup`事件被触发时，调用`search(term)`方法。
  
      The `search(term)` method delegates to our `WikipediaService` which returns an observable array of string results (`Observable<string[]`). 
      Instead of subscribing to the observable inside the component as we did in the `HeroListComponent`, 
      we forward the observable result to the template (via `items`) where the [async pipe](pipes.html#async-pipe)
      in the `ngFor` handles the subscription.
      
      `search(term)`方法委托我们的`WikipediaService`服务来完成实际操作。该服务返回的是一个字符串数组的可观察对象(`Observable<string[]`)。
      该组件的内部订阅了这个可观察对象，就像我们曾在`HeroListComponent`中所做的那样，
      我们把这个可观察对象作为结果传给模板（通过`items`属性），模板中`ngFor`上的[async(异步)管道](pipes.html#async-pipe)会对这个订阅进行处理。
    .l-sub-section
      :marked
        We often use the [async pipe](pipes.html#async-pipe) in read-only components where the component has no need to interact with the data.
        We couldn't use the pipe in the `HeroListComponent` because the "add hero" feature pushes newly created heroes into the list.
  
        我们通常在只读组件中使用[async管道](pipes.html#async-pipe)，这种组件不需要与数据进行互动。
        但我们不能在`HeroListComponent`中使用这个管道，这是因为“添加新英雄”特性会把一个新创建的英雄追加到英雄列表中。
    :marked
      ## Our wasteful app
      ## 我们这个奢侈的应用
  
      Our wikipedia search makes too many calls to the server. 
      It is inefficient and potentially expensive on mobile devices with limited data plans.
      
      我们这个Wikipedia搜索程序触发了过多的服务器调用（每次按键发一次）。
      这样效率很低，而且在流量受限的移动设备上会显得过于昂贵。
  
      ### 1. Wait for the user to stop typing
      ### 1. 等用户停止输入
      At the moment we call the server after every key stroke.
      The app should only make requests when the user *stops typing* .
      Here's how it *should* work &mdash; and *will* work  &mdash;  when we're done refactoring:
      
      现在，我们会在每次按键之后调用服务器。
      但合理的方式是只在用户*停止输入*之后才发起请求。
      这是它*应该*而且*即将使用*的工作方式，我们马上就重构它：
    figure.image-display
      img(src='/resources/images/devguide/server-communication/wiki-2.gif' alt="Wikipedia search app (v.2)" width="250")
    :marked
      ### 2. Search when the search term changes
      ### 2. 当搜索关键字变化了才搜索
  
      Suppose the user enters the word *angular* in the search box and pauses for a while. 
      The application issues a search request for *Angular*.
      
      假设用户在输入框中输入了单词*angular*，然后稍等片刻。
      应用程序就会发出一个对*Angular*的搜索请求。
  
      Then the user backspaces over the last three letters, *lar*, and immediately re-types *lar* before pausing once more.
      The search term is still "angular". The app shouldn't make another request.
      
      然后，用户用退格键删除了最后三个字符*lar*，并且毫不停顿的重新输入了*lar*。
      搜索关键词仍然是“angular”。这时应用程序不应该发起另一个请求。
  
      ### 3. Cope with out-of-order responses
      ### 3. 对付乱序响应体
  
      The user enters *angular*, pauses, clears the search box, and enters *http*. 
      The application issues two search requests, one for *angular* and one for *http*. 
      
      用户输入了*angular*，暂停，清除搜索框，然后输入*http*。
      应用程序发起了两个搜索请求，一个搜*angular*，一个搜*http*。
  
      Which response will arrive first? We can't be sure. 
      A load balancer could dispatch the requests to two different servers with different response times.
      The results from the first *angular* request might arrive after the later *http* results.
      The user will be confused if we display the *angular* results to the *http* query.
      
      哪一个响应会先回来？我们是没法保证的。
      负载均衡器可能把这个请求分发给了响应时间不同的两台服务器。
      来自第一个*angular*请求的结果可能晚于稍后的*http*的结果。
      用户可能会困惑：为什么在*http*请求中显示了*angular*的结果。
  
      When there are multiple requests in-flight, the app should present the responses
      in the original request order. That won't happen if *angular* results arrive last.
      
      如果有多个请求“打架”，应用程序应该按照原始请求的顺序展示对它们的响应。即使*angular*的结果后返回，也不会发生这样的混乱。
  
      <a id="more-observables"></a>
      ## More fun with Observables
      ## Observable的更多乐趣
      We can address these problems and improve our app with the help of some nifty observable operators. 
      
      借助一些漂亮的可观察对象操作函数，我们可以解决这些问题，并提升我们的应用程序。
  
      We could make our changes to the `WikipediaService`. 
      But we sense that our concerns are driven by the user experience so we update the component class instead.
      
      我们本可以把这些改动合并进`WikipediaService`中，但别忘了我们的关注点应该是由用户体验驱动的，所以，还是把它放到组件类中吧。
  
    +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', null, 'app/wiki/wiki-smart.component.ts')
    :marked
      We made no changes to the template or metadata, confining them all to the component class.
      Let's review those changes.
      
      我们没有修改模板或元数据，只改了组件类。
      我们来回顾一下这些改动。
  
      ### Create a stream of search terms
      ### 创建一个有搜索关键字组成的“流(Stream)”
  
      We're binding to the search box `keyup` event and calling the component's `search` method after each keystroke.
      
      我们正在绑定到搜索框的`keyup`事件，并且在每次按键之后调用组件的`search`方法。
  
      We turn these events into an observable stream of search terms using a `Subject` 
      which we import from the RxJS observable library:
      
      我们借助`Subject`类把这些事件转变成一个由搜索关键字组成的可观察的“流”对象。`Subject`是我们从RxJS库中导入的：
    +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'import-subject')
    :marked
      Each search term is a string, so we create a new `Subject` of type `string` called `searchTermStream`.
      After every keystroke, the `search` method adds the search box value to that stream
      via the subject's `next` method.
      
      每个搜索关键字都是一个字符串，所以我们创建了一个新的`string`类型的`Subject`，并把它称为`searchTermStream`。
      在每次按键之后，`search`方法都会通过`Subject`的`next`方法把搜索框的值添加到流中。
    +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'subject')(format='.')
    :marked
      ### Listen for search terms
      ### 监听搜索关键字
  
      Earlier, we passed each search term directly to the service and bound the template to the service results.
      Now we listen to the *stream of terms*, manipulating the stream before it reaches the `WikipediaService`.
      
      以前，我们每次都把搜索关键字直接传给服务，并且把模板绑定到服务返回的结果。
      而现在我们在监听*关键字组成的流*，并在把它传给`WikipediaService`之前操作这个流。
    +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'observable-operators')(format='.')
    :marked
      We wait for the user to stop typing for at least 300 milliseconds 
      ([debounceTime](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/debounce.md)).
      Only changed search values make it through to the service 
      ([distinctUntilChanged](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/distinctuntilchanged.md)).
      
      我们先等待用户停止输入至少300毫秒
      ([debounceTime](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/debounce.md))。
      只有当搜索关键字变化的时候，才把它传给服务
      ([distinctUntilChanged](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/distinctuntilchanged.md))。
  
      The `WikipediaService` returns a separate observable of string arrays (`Observable<string[]>`) for each request.
      We could have multiple requests *in flight*, all awaiting the server's reply,
      which means multiple *observables-of-strings* could arrive at any moment in any order.
      
      `WikipediaService`服务为每个请求返回一个独立的可观察的字符串数组(`Observable<string[]>`)。
      我们可以同时有多个*发送中*的请求，它们都在等服务器的回复，
      这意味着多个*可观察的字符串数组*有可能在任何时刻以任何顺序抵达。
  
      The [switchMap](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/flatmaplatest.md)
      (formerly known as `flatMapLatest`) returns a new observable that combines these `WikipediaService` observables, 
      re-arranges them in their original request order,
      and delivers to subscribers only the most recent search results. 
      
      [switchMap](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/flatmaplatest.md)(常被称为`flatMapLatest`)
      返回一个新的可观察对象，它组合了所有这些“可观察的字符串数组”，重新按照它们的原始请求顺序进行排列，然后把最近的一个搜索结果交付给调用者。
  
      The displayed list of search results stays in sync with the user's sequence of search terms.
      
      于是，最终显示的搜索结果列表和用户输入的搜索关键字在顺序上保持了一致。
    .l-sub-section
      :marked
        We added the `debounceTime`, `distinctUntilChanged`, and `switchMap` operators to the RxJS `Observable` class
        in `rxjs-operators` as [described above](#rxjs)
        
        在[前面提过的](#rxjs)`rxjs-operators`文件中，我们把`debounceTime`、`distinctUntilChanged`和`switchMap`操作函数加到了RxJS的`Observable`类中。
  
  a#in-mem-web-api
  .l-main-section
  :marked
    ## Appendix: Tour of Heroes in-memory server
    ## 附录：《英雄指南》的内存(in-memory)服务器
  
    If we only cared to retrieve data, we could tell Angular to get the heroes from a `heroes.json` file like this one:
    
    如果我们只关心获取到的数据，我们可以告诉Angular从一个从一个`heroes.json`文件中获取英雄列表，就像这样：
  +makeJson('server-communication/ts/app/heroes.json', null, 'app/heroes.json')(format=".")
  .l-sub-section
    :marked
      We wrap the heroes array in an object with a `data` property for the same reason that a data server does:
      to mitigate the [security risk](http://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk)
      posed by top-level JSON arrays. 
      
      我们把英雄数组包装在一个带有`data`属性的对象中，就像一个数据服务器所做的那样：
      用于缓解由顶层的JSON数组带来的[安全风险](http://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk)。
  :marked
    We'd set the endpoint to the JSON file like this:
    
    我们要像这样把端点设置为这个JSON文件：
  +makeExample('server-communication/ts/app/toh/hero.service.ts', 'endpoint-json')(format=".")
  
  - var _a_ca_class_with = _docsFor === 'ts' ? 'a custom application class with' : ''
  