利用Angular2的Observables实现交互控制的方法

在Angular1.x中,我们使用Promise来处理各种异步。但是在angular2中,使用的是Reactive Extensions (Rx)的Observable。对于Promise和Observable的区别,网上有很多文章,推荐egghead.io上的这个7分钟的视频(作者 Ben Lesh)。在这个视频的介绍中,主要说的,使用Observable创建的异步任务,可以被处理,而且是延时加载的。这篇文章里,我们主要针对一些在跟服务器端交互的时候遇到的问题,来看看Observable给我们带来的特性。

实例场景

首先,我们来定义一下问题的场景。假设我们要实现一个搜索功能,有一个简单的输入框,当用户输入文字的时候,实时的利用输入的文字进行查询,并显示查询的结果。

问题

在这个简单的场景当中,一般需要考虑3个问题:

不能在用户输入每个字符的时候就触发搜索。

如果用户输入每个字符就触发搜索,一来浪费服务器资源,二来客户端频繁触发搜索,以及更新搜索结果,也会影响客户端的响应。一般这个问题,都是通过加一些延时来避免。

如果用户输入的文本没有变化,就不应该重新搜索。

假设用户输入了'foo'以后,停顿了一会,触发了搜索,再敲了一个字符'o',结果发现打错了,又删掉了这个字符。如果这个时候用户又停顿一会,导致触发了搜索,这次的文本'foo'跟之前搜索的时候的文本是一样的,所以不应该再次搜索。

要考虑服务器的异步返回的问题。

当我们使用异步的方式往服务器端发送多个请求的时候,我们需要注意接受返回的顺序是无法保证的。比如我们先后搜索了2个单词'computer', ‘car', 虽然'car'这个词是后来搜的,但是有可能服务器处理这个搜索比较快,就先返回结果。这样页面就会先显示'car'的搜索结果,然后等收到'computer'的搜索结果的时候,再显示'computer'的结果。但是,这时候在用户看来明明搜索的是'car',却显示的是另外的结果。

迎接挑战

在这个实例中,我们使用wikipedia的api接口来开发一个简单的实例,实现简单的搜索功能。

实现搜索

由于只是演示,我们的app里面只包含2个文件: app.ts 和 wikipedia-service.ts,最终版本的源文件,请参考原文提供的demo链接。

我们直接来看最初版本的WikipediaService是如何实现的:

import { Injectable } from '@angular/core'; import { URLSearchParams, Jsonp } from '@angular/http'; @Injectable() export class WikipediaService { constructor(private jsonp: Jsonp) {} search (term: string) { var search = new URLSearchParams() search.set('action', 'opensearch'); search.set('search', term); search.set('format', 'json'); return this.jsonp .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search }) .toPromise() .then((response) => response.json()[1]); } }

在这里版本中,使用Jsonp模块来请求api结果,它的结果应该是一个类型为Observable<Response>的对象,我们把返回的结果从Observable<Response> 转换成 Promise<Response>对象,然后使用它的then方法把结果转成json。这样,这个search方法的返回类型为Promise<Array<string>>。

注意上面,我们使用response.json()[1]方式,从原先的结果中,得到我们需要的查询结果的列表,列表里面都是string。

这个看起来很简单,在angular1.x里面,也基本都是使用$http或$resource,来返回一个Promise类型的结果。

下面就是app.ts的部分内容(因为这只是演示,所以直接在app.ts里面直接定义module和component,并且调用service,在真实的app中,应该创建相应的组件来实现):

// check the plnkr for the full list of imports import {...} from '...'; @Component({ selector: 'my-app', template: ` <div> <h2>Wikipedia Search</h2> <input #term type="text" (keyup)="search(term.value)"> <ul> <li *ngFor="let item of items">{{item}}</li> </ul> </div> ` }) export class AppComponent { items: Array<string>; constructor(private wikipediaService: WikipediaService) {} search(term) { this.wikipediaService.search(term).then(items => this.items = items); } }

从上面的代码也能看出,AppComponent有一个search()方法,它调用wikipediaService.search()方法,因为这个方法返回一个Promise<Array<string>>类型的结果,所以使用then(),把结果列表赋值给model对象items。上面的template里面的模板内容就是用来以列表显示查询的结果。

虽然这个实现满足了基本的查询功能,但是对于上面提到的3个问题,都没有能够解决。下面就来修改这个实现来解决上面的问题。

控制用户输入延时

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/c40e4132695f91cde35841d5bfa43a7d.html