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:     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. 
  
      As always, we wrap our interaction with an Angular data access client service inside a dedicated service, here called `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`.
  
    <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.
    .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.
    :marked
      If we're looking for articles with the word "Angular", we could construct the query string by hand and call `jsonp` like this:
    +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:
    +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.
    +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.
  
    <a id="wikicomponent"></a>
    :marked
      ### The 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.
  
    +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`.
  
      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.
  
      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.
    .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.
  
    :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.
  
      ### 1. Wait for the user to stop typing
      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
  
      Suppose the user enters the word *angular* in the search box and pauses for a while. 
      The application issues a search request for *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.
  
      ### 3. Cope with out-of-order responses
  
      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*. 
  
      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.
  
      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.
  
      <a id="more-observables"></a>
      ## More fun with Observables
      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.
  
    +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
  
      We're binding to the search box `keyup` event and calling the component's `search` method after each keystroke.
  
      We turn these events into an observable stream of search terms using a `Subject` 
      which we import from the RxJS observable library:
    +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.
    +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`.
    +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)).
  
      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.
  
      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. 
  
      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)
  
  a#in-mem-web-api
  .l-main-section
  :marked
    ## Appendix: Tour of Heroes in-memory server
  
    If we only cared to retrieve data, we could tell Angular to get the heroes from a `heroes.json` file like this one:
  +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. 
  :marked
    We'd set the endpoint to the JSON file like this:
  +makeExample('server-communication/ts/app/toh/hero.service.ts', 'endpoint-json')(format=".")
  
  - var _a_ca_class_with = _docsFor === 'ts' ? 'a custom application class with' : ''
  
negative.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`)
      
      内存Web API不是Angular内核的一部分。
      它是一个可选的服务，来自独立的`angular2-in-memory-web-api`库。我们可以通过npm(参见`package.json`)来安装它，
      并且通过SystemJS(参见`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.
    
    内存Web API从一个带有`createDb()`方法的自定义类中获取数据，并且返回一个map，它的主键(key)是一组名字，而值(value)是一组与之对应的对象数组。
    
    Here's the class we created for this sample based on the JSON data:
    
    这里是与范例中那个基于JSON的数据源完成相同功能的类：
  +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:
    
    确保`HeroService`的端点指向了这个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.
    
    最后，我们需要把来自HTTP客户端的请求重定向到这个内存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`. 
      
      这次重定向非常易于配置，这是因为Angular的`http`服务把客户端/服务器通讯的工作委托给了一个叫做`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.
      
      要想启用我们的服务模拟器，我们通过Angular标准的“供应商注册”技术，把默认的`XHRBackend`服务替换为了这个内存Web API服务。
      同时，我们使用来自模拟的英雄数据集的*种子数据*初始化了这个内存Web API。
  
  p Here is the revised (and final) version of the #[code #[+adjExPath('app/main.ts')]] demonstrating these steps.
  
  p 下面是修改过的（也是最终的）#[code #[+adjExPath('app/main.ts')]]版本，用于演示这些步骤。
  +makeExample('server-communication/ts/app/main.ts', 'final', 'app/main.ts (final)')(format=".")
  
  p See the full source code in the #[+liveExampleLink2()].
  p 要想查看完整的源代码，参见#[+liveExampleLink2('浏览器中运行在线版')]。
  