日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用Angular2的Observables实现交互控制

發(fā)布時間:2025/5/22 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用Angular2的Observables实现交互控制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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

實例場景

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

問題

在這個簡單的場景當(dāng)中,一般需要考慮3個問題:

  • 不能在用戶輸入每個字符的時候就觸發(fā)搜索。
    如果用戶輸入每個字符就觸發(fā)搜索,一來浪費服務(wù)器資源,二來客戶端頻繁觸發(fā)搜索,以及更新搜索結(jié)果,也會影響客戶端的響應(yīng)。一般這個問題,都是通過加一些延時來避免。
  • 如果用戶輸入的文本沒有變化,就不應(yīng)該重新搜索。
    假設(shè)用戶輸入了’foo’以后,停頓了一會,觸發(fā)了搜索,再敲了一個字符’o’,結(jié)果發(fā)現(xiàn)打錯了,又刪掉了這個字符。如果這個時候用戶又停頓一會,導(dǎo)致觸發(fā)了搜索,這次的文本’foo’跟之前搜索的時候的文本是一樣的,所以不應(yīng)該再次搜索。
  • 要考慮服務(wù)器的異步返回的問題。
    當(dāng)我們使用異步的方式往服務(wù)器端發(fā)送多個請求的時候,我們需要注意接受返回的順序是無法保證的。比如我們先后搜索了2個單詞’computer’, ‘car’, 雖然’car’這個詞是后來搜的,但是有可能服務(wù)器處理這個搜索比較快,就先返回結(jié)果。這樣頁面就會先顯示’car’的搜索結(jié)果,然后等收到’computer’的搜索結(jié)果的時候,再顯示’computer’的結(jié)果。但是,這時候在用戶看來明明搜索的是’car’,卻顯示的是另外的結(jié)果。

迎接挑戰(zhàn)

在這個實例中,我們使用wikipedia的api接口來開發(fā)一個簡單的實例,實現(xiàn)簡單的搜索功能。

實現(xiàn)搜索

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

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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結(jié)果,它的結(jié)果應(yīng)該是一個類型為Observable<Response>的對象,我們把返回的結(jié)果從Observable<Response>?轉(zhuǎn)換成?Promise<Response>對象,然后使用它的then方法把結(jié)果轉(zhuǎn)成json。這樣,這個search方法的返回類型為Promise<Array<string>>。

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

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

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 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()方法,它調(diào)用wikipediaService.search()方法,因為這個方法返回一個Promise<Array<string>>類型的結(jié)果,所以使用then(),把結(jié)果列表賦值給model對象items。上面的template里面的模板內(nèi)容就是用來以列表顯示查詢的結(jié)果。

雖然這個實現(xiàn)滿足了基本的查詢功能,但是對于上面提到的3個問題,都沒有能夠解決。下面就來修改這個實現(xiàn)來解決上面的問題。

控制用戶輸入延時

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

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

1 2 3 4 5 6 7 8 9 10 11 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來創(chuàng)建表單輸入,并給他設(shè)置一個變量名term。

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

?

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

1 2 3 4 5 6 7 8 9 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是一個Observable<string>對象,通過debounceTime(400)我們設(shè)置它的事件觸發(fā)延時是400毫秒。這個方法還是返回一個Observable<string>對象。然后我們就給這個對象添加一個訂閱事件:

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

?

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

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

防止觸發(fā)兩次

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

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

處理返回順序

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

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

1 2 3 4 5 6 7 8 9 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]); }

?

注意這個方法最后用.map((response) => response.json()[1]),意思是對于原先的Response類型的結(jié)果,轉(zhuǎn)換成實際的搜索結(jié)果的列表。
map()以及后面要說到的flatMap()之類的方法,是函數(shù)式編程里面常用到的方法,意思就是將原先的數(shù)據(jù)集里面的每一條數(shù)據(jù),經(jīng)過一定的處理再返回一個新的結(jié)果,也就是把一個數(shù)據(jù)集轉(zhuǎn)換成另一個數(shù)據(jù)集。

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

1 2 3 4 5 6 7 8 this.term.valueChanges .debounceTime(400) .distinctUntilChanged() .subscribe( term => this.wikipediaService.search(term).subscribe( items => this.items = items ) );

?

其中,第一個subscribe():

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

?

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

第二個subscribe():

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

?

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

我們也可以用下面的方式,來避免這樣使用多個subscribe:

1 2 3 4 5 this.term.valueChanges .debounceTime(400) .distinctUntilChanged() .flatMap(term => this.wikipediaService.search(term)) .subscribe(items => this.items = items);

?

我們在用戶輸入的字符串的Observable<string>上調(diào)用flatMap(...)方法,相當(dāng)于,對用戶輸入的每個有效的查詢條件,調(diào)用wikipediaService.search()方法。然后對這個查詢返回的數(shù)據(jù),再注冊一個訂閱方法。

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

費了這么大功夫,上面說的似乎跟’忽略之前未及時返回的消息’好像沒什么關(guān)系,那么上面的修改到底有沒有解決那個問題呢。沒有!確實是沒有。因為我們使用flatMap,對用戶輸入的每個有效的查詢字符串,都會調(diào)用訂閱的那個處理函數(shù),然后更新model。所以我們的問題還是沒有解決。

但是到了這一步以后,解決辦法就很容易了,我們只需要用switchMap代理flatMap就可以。就這么簡單!這是因為,switchMap會在處理每一個新的消息的時候,就直接把上一個消息注冊的訂閱方法直接取消掉。

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @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對象this.items,也就是一個Observable<Array<string>>類型的數(shù)據(jù)。這樣,在模板里面使用items的地方也需要修改,使用AsyncPipe就可以:

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

?

這樣,模板在解析items這個model的時候,就會自動解析這個Observable的結(jié)果,再渲染頁面。

Demo地址:?Smart Wikipedia search using Angular 2

轉(zhuǎn)載于:https://www.cnblogs.com/airen123/p/9050815.html

總結(jié)

以上是生活随笔為你收集整理的利用Angular2的Observables实现交互控制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 极品女神无套呻吟啪啪 | 国产swag在线 | 国产精品作爱 | 亚洲伦理一区二区 | 五月天色综合 | 精品一区二区无码 | 久久精品国产亚洲av嫖农村妇女 | 紧身裙女教师三上悠亚红杏 | 日本做爰全过程免费看 | 国产日韩高清在线 | 国产一区二区在线不卡 | 午夜爱爱毛片xxxx视频免费看 | 一级爱爱片 | 精品人妻久久久久久888不卡 | 一区日韩 | 高清av网址 | 高清不卡一区 | 99reav| 99r在线视频 | 日美韩一区二区三区 | 日韩成人在线视频观看 | 欧美绿帽交换xxx | 黄色片免费观看视频 | 成人免费视频网站在线看 | av新天堂| 国产精品成人无码专区 | 中国一及毛片 | 久久婷色 | 免费在线看视频 | 风韵丰满熟妇啪啪区老熟熟女 | 双性人bbww欧美双性 | a免费观看 | 国产日韩欧美在线观看视频 | 日韩91视频| 欧美一级在线观看视频 | 美女裸体跪姿扒开屁股无内裤 | 色屁屁www | 又大又粗欧美黑人aaaaa片 | 日韩在线观看视频一区二区三区 | 日日碰日日摸 | 天堂网中文 | 亚洲视频一二三区 | 一本色道久久综合无码人妻 | www.三级 | 欧美 国产 精品 | 欧美偷拍一区二区三区 | 一道本久在线中文字幕 | 日韩中文字幕av在线 | 校霸被c到爽夹震蛋上课高潮 | 欧美日韩在线免费 | 视频一区免费 | 偷偷操视频 | 亚洲激情欧美色图 | 日韩成人av网站 | 国产第一精品 | 亚洲一区二区精品在线观看 | 国产精品另类 | 久久叉 | 久草久操| 综合久| 欧美成人手机在线视频 | 色悠悠网| 欧美偷拍精品 | 久久国产这里只有精品 | 有奶水的迷人少妇 | 精品视频网站 | 国产欧美高清 | 日本不卡一区二区在线观看 | 自拍三级 | 欧美日韩图片 | 黄色操人视频 | 久久毛片 | 午夜天堂精品 | 成年人国产 | 日韩视频一区二区在线观看 | 四虎在线精品 | 免费观看污视频 | 一亲二脱三插 | 青草精品视频 | 亚洲免费在线看 | 亚洲在线一区 | 久久精品123 | 亚洲88av| 一级二级在线观看 | 91精品视频在线 | 青青免费视频 | 超碰中文字幕在线 | 日本wwwxxx| 高潮毛片无遮挡高清免费 | 日韩视频免费在线 | 俄罗斯精品一区二区三区 | 中文字幕亚洲精品在线 | 成人精品视频一区二区三区尤物 | 久草国产在线视频 | 1515hh成人免费看 | 一级黄在线观看 | 黄色片久久 | 欧美在线精品一区 | 狠狠鲁影院 |