最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用Angular2的Observables實(shí)現(xiàn)交互控制的方法

 更新時(shí)間:2018年12月27日 09:50:55   作者:ztguang  
這篇文章主要介紹了利用Angular2的Observables實(shí)現(xiàn)交互控制的方法,我們主要針對(duì)一些在跟服務(wù)器端交互的時(shí)候遇到的問(wèn)題,來(lái)看看Observable給我們帶來(lái)的特性。感興趣的可以了解一下

在Angular1.x中,我們使用Promise來(lái)處理各種異步。但是在angular2中,使用的是Reactive Extensions (Rx)的Observable。對(duì)于Promise和Observable的區(qū)別,網(wǎng)上有很多文章,推薦egghead.io上的這個(gè)7分鐘的視頻(作者 Ben Lesh)。在這個(gè)視頻的介紹中,主要說(shuō)的,使用Observable創(chuàng)建的異步任務(wù),可以被處理,而且是延時(shí)加載的。這篇文章里,我們主要針對(duì)一些在跟服務(wù)器端交互的時(shí)候遇到的問(wèn)題,來(lái)看看Observable給我們帶來(lái)的特性。

實(shí)例場(chǎng)景

首先,我們來(lái)定義一下問(wèn)題的場(chǎng)景。假設(shè)我們要實(shí)現(xiàn)一個(gè)搜索功能,有一個(gè)簡(jiǎn)單的輸入框,當(dāng)用戶輸入文字的時(shí)候,實(shí)時(shí)的利用輸入的文字進(jìn)行查詢,并顯示查詢的結(jié)果。

問(wèn)題

在這個(gè)簡(jiǎn)單的場(chǎng)景當(dāng)中,一般需要考慮3個(gè)問(wèn)題:

不能在用戶輸入每個(gè)字符的時(shí)候就觸發(fā)搜索。

如果用戶輸入每個(gè)字符就觸發(fā)搜索,一來(lái)浪費(fèi)服務(wù)器資源,二來(lái)客戶端頻繁觸發(fā)搜索,以及更新搜索結(jié)果,也會(huì)影響客戶端的響應(yīng)。一般這個(gè)問(wèn)題,都是通過(guò)加一些延時(shí)來(lái)避免。

如果用戶輸入的文本沒(méi)有變化,就不應(yīng)該重新搜索。

假設(shè)用戶輸入了'foo'以后,停頓了一會(huì),觸發(fā)了搜索,再敲了一個(gè)字符'o',結(jié)果發(fā)現(xiàn)打錯(cuò)了,又刪掉了這個(gè)字符。如果這個(gè)時(shí)候用戶又停頓一會(huì),導(dǎo)致觸發(fā)了搜索,這次的文本'foo'跟之前搜索的時(shí)候的文本是一樣的,所以不應(yīng)該再次搜索。

要考慮服務(wù)器的異步返回的問(wèn)題。

當(dāng)我們使用異步的方式往服務(wù)器端發(fā)送多個(gè)請(qǐng)求的時(shí)候,我們需要注意接受返回的順序是無(wú)法保證的。比如我們先后搜索了2個(gè)單詞'computer', ‘car', 雖然'car'這個(gè)詞是后來(lái)搜的,但是有可能服務(wù)器處理這個(gè)搜索比較快,就先返回結(jié)果。這樣頁(yè)面就會(huì)先顯示'car'的搜索結(jié)果,然后等收到'computer'的搜索結(jié)果的時(shí)候,再顯示'computer'的結(jié)果。但是,這時(shí)候在用戶看來(lái)明明搜索的是'car',卻顯示的是另外的結(jié)果。

迎接挑戰(zhàn)

在這個(gè)實(shí)例中,我們使用wikipedia的api接口來(lái)開(kāi)發(fā)一個(gè)簡(jiǎn)單的實(shí)例,實(shí)現(xiàn)簡(jiǎn)單的搜索功能。

實(shí)現(xiàn)搜索

由于只是演示,我們的app里面只包含2個(gè)文件: app.ts 和 wikipedia-service.ts,最終版本的源文件,請(qǐng)參考原文提供的demo鏈接。

我們直接來(lái)看最初版本的WikipediaService是如何實(shí)現(xiàn)的:

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模塊來(lái)請(qǐng)求api結(jié)果,它的結(jié)果應(yīng)該是一個(gè)類(lèi)型為Observable<Response>的對(duì)象,我們把返回的結(jié)果從Observable<Response> 轉(zhuǎn)換成 Promise<Response>對(duì)象,然后使用它的then方法把結(jié)果轉(zhuǎn)成json。這樣,這個(gè)search方法的返回類(lèi)型為Promise<Array<string>>。

注意上面,我們使用response.json()[1]方式,從原先的結(jié)果中,得到我們需要的查詢結(jié)果的列表,列表里面都是string。

這個(gè)看起來(lái)很簡(jiǎn)單,在angular1.x里面,也基本都是使用$http或$resource,來(lái)返回一個(gè)Promise類(lèi)型的結(jié)果。

下面就是app.ts的部分內(nèi)容(因?yàn)檫@只是演示,所以直接在app.ts里面直接定義module和component,并且調(diào)用service,在真實(shí)的app中,應(yīng)該創(chuàng)建相應(yīng)的組件來(lái)實(shí)現(xiàn)):

// 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有一個(gè)search()方法,它調(diào)用wikipediaService.search()方法,因?yàn)檫@個(gè)方法返回一個(gè)Promise<Array<string>>類(lèi)型的結(jié)果,所以使用then(),把結(jié)果列表賦值給model對(duì)象items。上面的template里面的模板內(nèi)容就是用來(lái)以列表顯示查詢的結(jié)果。

雖然這個(gè)實(shí)現(xiàn)滿足了基本的查詢功能,但是對(duì)于上面提到的3個(gè)問(wèn)題,都沒(méi)有能夠解決。下面就來(lái)修改這個(gè)實(shí)現(xiàn)來(lái)解決上面的問(wèn)題。

控制用戶輸入延時(shí)

我們先解決第一個(gè)問(wèn)題:當(dāng)用戶輸入的時(shí)候,不要每次輸入一個(gè)字符就觸發(fā)一次搜索,而是設(shè)置一個(gè)時(shí)間延時(shí),當(dāng)用戶停止輸入的時(shí)間超過(guò)400毫秒,就觸發(fā)搜索。如果用戶一直不停的輸入,輸入的時(shí)間間隔小于400ms就不觸發(fā)。這正是'Observables'能做的事情。

為此,我們需要一個(gè)Observable<string>對(duì)象來(lái)保存用戶的輸入,然后就可以用這個(gè)對(duì)象提供的方法來(lái)實(shí)現(xiàn)延時(shí)觸發(fā)的功能。我們可以利用Angular2的指令(directive)formControl。要用這個(gè)指令,需要引入ReactiveFormsModule模塊。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { JsonpModule } from '@angular/http';
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [BrowserModule, JsonpModule, ReactiveFormsModule]
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}

引入以后,我們就可以在模板里面使用FormControl來(lái)創(chuàng)建表單輸入,并給他設(shè)置一個(gè)變量名term。

<input type="text" [formControl]="term"/>

這樣,這個(gè)input組件所綁定的變量term就是FormControl的一個(gè)實(shí)例,它有一個(gè)屬性valueChanges,這個(gè)屬性是一個(gè)Observable<string>類(lèi)型的對(duì)象。我們就可以使用Observable<string>的debounceTime方法來(lái)設(shè)置觸發(fā)延時(shí)。

export class AppComponent {
items: Array<string>;
term = new FormControl();
constructor(private wikipediaService: WikipediaService) {
this.term.valueChanges
.debounceTime(400)
.subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));
}
}

我們看到this.term.valueChanges是一個(gè)Observable<string>對(duì)象,通過(guò)debounceTime(400)我們?cè)O(shè)置它的事件觸發(fā)延時(shí)是400毫秒。這個(gè)方法還是返回一個(gè)Observable<string>對(duì)象。然后我們就給這個(gè)對(duì)象添加一個(gè)訂閱事件:

term => this.wikipediaService.search(term).then(items => this.items = items)

這是用lambda表達(dá)式寫(xiě)的一個(gè)方法。參數(shù)term就是Observable<string>對(duì)象經(jīng)過(guò)400ms的延時(shí)設(shè)置,產(chǎn)生的一個(gè)用戶輸入的字符串。方法體就是用這個(gè)參數(shù)進(jìn)行搜索,跟之前版本的處理方式一致。

在這個(gè)修改版中,我們把之前的search()方法去掉,直接在構(gòu)造函數(shù)constructor(...)里面添加的,這相當(dāng)于,用戶在輸入框的輸入,是一個(gè)消息源,會(huì)經(jīng)過(guò)debounceTime(400)的處理,然后產(chǎn)生一個(gè)消息,這個(gè)消息會(huì)發(fā)送給訂閱的事件處理函數(shù)來(lái)處理,也就是搜索。所以,我們不需要一個(gè)search()方法來(lái)控制什么時(shí)候觸發(fā),而是通過(guò)類(lèi)型訂閱的機(jī)制來(lái)處理用戶輸入。

防止觸發(fā)兩次

現(xiàn)在我們?cè)賮?lái)解決第二個(gè)問(wèn)題,就是經(jīng)過(guò)400ms的延時(shí)以后,用戶輸入的搜索條件一樣的情況。有了上面的Observable,這個(gè)就很簡(jiǎn)單了,Observable有一個(gè)distinctUntilChanged的方法,他會(huì)判斷從消息源過(guò)來(lái)的新數(shù)據(jù)跟上次的數(shù)據(jù)是否一致,只有不一致才會(huì)觸發(fā)訂閱的方法。

this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));

處理返回順序

上面描述了服務(wù)器端異步返回?cái)?shù)據(jù)的時(shí)候,返回順序不一致出現(xiàn)的問(wèn)題。對(duì)于這個(gè)問(wèn)題,我們的解決辦法就比較直接,也就是對(duì)于之前的請(qǐng)求返回的結(jié)果,直接忽略,只處理在頁(yè)面上用戶最后一次發(fā)起的請(qǐng)求的結(jié)果。說(shuō)道忽略之前的請(qǐng)求,如果你們看了上面的視頻,或者知道Promise和Observable的區(qū)別的話,就應(yīng)該想到我們可以利用Observable的dispose()方法來(lái)解決。實(shí)際上,我們是利用這種'disposable'特性來(lái)解決,而不是直接調(diào)用dispose()方法。(實(shí)在不知道該怎么翻譯'disposable',它的意思是我可以中止在Observable對(duì)象上的消息處理,字面的意思是可被丟棄的、一次性的。)

上面我們講到,在service的search()方法里,我們把Jsonp返回的結(jié)果從Observable<Response> 轉(zhuǎn)換成 Promise<Response>對(duì)象。為了利用Observable的特性去丟棄上一個(gè)未及時(shí)返回的結(jié)果,我們讓這個(gè)方法還是返回Observable類(lèi)型的結(jié)果。下面就是修改后的WikipediaService里面的search()方法。

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 })
.map((response) => response.json()[1]);
}

注意這個(gè)方法最后用.map((response) => response.json()[1]),意思是對(duì)于原先的Response類(lèi)型的結(jié)果,轉(zhuǎn)換成實(shí)際的搜索結(jié)果的列表。

map()以及后面要說(shuō)到的flatMap()之類(lèi)的方法,是函數(shù)式編程里面常用到的方法,意思就是將原先的數(shù)據(jù)集里面的每一條數(shù)據(jù),經(jīng)過(guò)一定的處理再返回一個(gè)新的結(jié)果,也就是把一個(gè)數(shù)據(jù)集轉(zhuǎn)換成另一個(gè)數(shù)據(jù)集。

現(xiàn)在,我們的WikipediaSerice的返回結(jié)果就不是Promise了,所以我們就需要修改app.ts,我們不能再使用then()方法來(lái)處理結(jié)果,而是使用subscribe()添加一個(gè)消息訂閱方法。

this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.subscribe(
term => this.wikipediaService.search(term).subscribe(
items => this.items = items
)
);

其中,第一個(gè)subscribe():

this.term.valueChanges...subscribe(term => ....)

這個(gè)是對(duì)輸入框產(chǎn)生的查詢字符串,注冊(cè)一個(gè)訂閱方法,來(lái)處理用戶的輸入。

第二個(gè)subscribe():

this.wikipediaService.search(term).subscribe(items => this.items = items));

是對(duì)從服務(wù)器端返回的數(shù)據(jù)查詢結(jié)果,注冊(cè)一個(gè)訂閱方法,來(lái)將這個(gè)數(shù)據(jù)賦值到model上。

我們也可以用下面的方式,來(lái)避免這樣使用多個(gè)subscribe:

this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.flatMap(term => this.wikipediaService.search(term))
.subscribe(items => this.items = items);

我們?cè)谟脩糨斎氲淖址腛bservable<string>上調(diào)用flatMap(...)方法,相當(dāng)于,對(duì)用戶輸入的每個(gè)有效的查詢條件,調(diào)用wikipediaService.search()方法。然后對(duì)這個(gè)查詢返回的數(shù)據(jù),再注冊(cè)一個(gè)訂閱方法。

費(fèi)了這么大的篇幅,希望你明白了Observable的flatMap和subscribe用法,對(duì)于沒(méi)有接觸過(guò)函數(shù)式編程的人來(lái)說(shuō),這確實(shí)不好理解,但是在Angular2里面,我們將會(huì)大量使用各種函數(shù)式編程的方法。所以還是需要你花時(shí)間慢慢理解。

費(fèi)了這么大功夫,上面說(shuō)的似乎跟'忽略之前未及時(shí)返回的消息'好像沒(méi)什么關(guān)系,那么上面的修改到底有沒(méi)有解決那個(gè)問(wèn)題呢。沒(méi)有!確實(shí)是沒(méi)有。因?yàn)槲覀兪褂胒latMap,對(duì)用戶輸入的每個(gè)有效的查詢字符串,都會(huì)調(diào)用訂閱的那個(gè)處理函數(shù),然后更新model。所以我們的問(wèn)題還是沒(méi)有解決。

但是到了這一步以后,解決辦法就很容易了,我們只需要用switchMap代理flatMap就可以。就這么簡(jiǎn)單!這是因?yàn)?,switchMap會(huì)在處理每一個(gè)新的消息的時(shí)候,就直接把上一個(gè)消息注冊(cè)的訂閱方法直接取消掉。

最后,再優(yōu)化一下代碼:

@Component({
selector: 'my-app',
template: `
<div>
<h2>Wikipedia Search</h2>
<input type="text" [formControl]="term"/>
<ul>
<li *ngFor="let item of items | async">{{item}}</li>
</ul>
</div>
`
})
export class AppComponent {
items: Observable<Array<string>>;
term = new FormControl();
constructor(private wikipediaService: WikipediaService) {
this.items = this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.switchMap(term => this.wikipediaService.search(term));
}
}

我們直接把switchMap()的結(jié)果,賦給model對(duì)象this.items,也就是一個(gè)Observable<Array<string>>類(lèi)型的數(shù)據(jù)。這樣,在模板里面使用items的地方也需要修改,使用AsyncPipe就可以:

<li *ngFor="let item of items | async">{{item}}</li>

這樣,模板在解析items這個(gè)model的時(shí)候,就會(huì)自動(dòng)解析這個(gè)Observable的結(jié)果,再渲染頁(yè)面。

Demo地址: Smart Wikipedia search using Angular 2

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • angular6 填坑之sdk的方法

    angular6 填坑之sdk的方法

    這篇文章主要介紹了angular6 填坑之sdk的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • Angular中的請(qǐng)求攔截的方法

    Angular中的請(qǐng)求攔截的方法

    我們的接口是單獨(dú)編寫(xiě)的處理的,在實(shí)際的開(kāi)發(fā)項(xiàng)目中,有眾多的接口,有些需要登陸憑證,有些不需要。一個(gè)一個(gè)接口處理不妥,我們是否可以考慮對(duì)請(qǐng)求進(jìn)行攔截封裝,感興趣的可以了解一下
    2022-04-04
  • angularjs下拉框空白的解決辦法

    angularjs下拉框空白的解決辦法

    這篇文章主要為大家詳細(xì)介紹了angularjs下拉框空白的解決方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 淺談angular.js跨域post解決方案

    淺談angular.js跨域post解決方案

    本篇文章主要介紹了淺談angular.js跨域post解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 詳解Angular Forms中自定義ngModel綁定值的方式

    詳解Angular Forms中自定義ngModel綁定值的方式

    在Angular應(yīng)用中有兩種方式來(lái)實(shí)現(xiàn)表單綁定,但是對(duì)于一些特殊的表單控件沒(méi)法實(shí)現(xiàn),這篇文章主要介紹了詳解Angular Forms中自定義ngModel綁定值的方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • AngularJS實(shí)現(xiàn)網(wǎng)站換膚實(shí)例

    AngularJS實(shí)現(xiàn)網(wǎng)站換膚實(shí)例

    這篇文章主要為大家詳細(xì)介紹了AngularJS實(shí)現(xiàn)網(wǎng)站換膚的簡(jiǎn)單實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Angular5集成eventbus的示例代碼

    Angular5集成eventbus的示例代碼

    這篇文章主要介紹了Angular5集成eventbus的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Web前端框架Angular4.0.0 正式版發(fā)布

    Web前端框架Angular4.0.0 正式版發(fā)布

    經(jīng)歷了 6 個(gè) RC 版本之后,Angular 發(fā)布了 4.0.0 正式版。下面這篇文章主要給大家介紹了關(guān)于Web前端框架Angular4.0.0 正式版發(fā)布的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友們下面來(lái)一起看看吧。
    2017-03-03
  • AngularJS HTML DOM詳解及示例代碼

    AngularJS HTML DOM詳解及示例代碼

    本文主要介紹AngularJS HTML DOM基礎(chǔ)知識(shí),這里整理了相關(guān)資料和示例代碼進(jìn)行詳解,有需要的小伙伴可以參考下
    2016-08-08
  • AngularJS基礎(chǔ) ng-model 指令詳解及示例代碼

    AngularJS基礎(chǔ) ng-model 指令詳解及示例代碼

    本文主要介紹AngularJS ng-model 指令,這里幫大家整理了ng-model的基本資料,并附有示例代碼,有需要的小伙伴可以參考下
    2016-08-08

最新評(píng)論

左云县| 上饶市| 将乐县| 正宁县| 介休市| 岳西县| 黄陵县| 开鲁县| 张家口市| 茂名市| 施秉县| 曲阳县| 东乌珠穆沁旗| 天柱县| 开平市| 鄢陵县| 通河县| 济阳县| 淮滨县| 岳西县| 玉屏| 贡觉县| 胶州市| 南陵县| 枝江市| 双峰县| 原平市| 盐源县| 诸暨市| 和政县| 宁南县| 穆棱市| 天峻县| 三门县| 尚志市| 革吉县| 隆安县| 东宁县| 仁布县| 东丽区| 三明市|