angular度 – 诺言与可观察
有人可以解释一下我的Promise
vs Observable
in Angular吗?
每个样本都将有助于理解这两种情况。 什么时候使用情况下的每个案例。
诺言
Promise
在asynchronous操作完成或失败时处理单个事件 。
注意:有Promise
库支持取消,但是ES6 Promise
目前还没有。
可观察
一个Observable
就像一个Stream
(在很多语言中),并允许传递零个或多个事件,每个事件都要调用callback函数。
通常Observable
比Promise
更Promise
因为它提供了Promise
等特性。 有了Observable
,如果要处理0,1个或多个事件,则无关紧要。 您可以在每种情况下使用相同的API。
Observable
也有优于可撤销的优势。 如果不再需要向服务器发送HTTP请求的结果或其他昂贵的asynchronous操作,则Observable
的Subscription
允许取消订阅,而Promise
最终将调用成功或失败的callback,即使您不需要通知或其提供的结果。
Observable提供了像map
, forEach
, reduce
等操作符 ,类似于一个数组
还有像retry()
或replay()
这样的强大的操作符,这些操作符通常非常方便。
! 承诺vs观察
- 诺言:
- 返回单个值
- 不可取消
- 可观察
- 随着时间的推移有多个价值观
- 撤销
- 支持地图,过滤,缩小和类似的操作
- 为ES 2016提出的function
- 使用Reactive Extensions(RxJS)
- 其项目随时间asynchronous到达的数组
Promises
和Observables
为我们提供了抽象,帮助我们处理应用程序的asynchronous性。 @Günter和@Relu明确指出了他们之间的区别。
由于代码片段胜过千言万语,请通过下面的示例来更容易地理解它们。
感谢@Christoph Burgdorf的精彩文章
Angular使用Rx.js Observable而不是承诺处理HTTP。
假设你正在build立一个searchfunction ,在你键入的时候应该立即显示你的结果。 听起来很熟悉,但是这个任务带来了很多挑战。
- 我们不希望每次用户按下某个键时都碰到服务器端点,应该用
HTTP
请求的风暴来洪泛它们。 基本上,我们只想在用户停止input而不是每次击键时都击中它。 - 不要使用相同的查询参数来为后续请求命中search端点。
- 处理无序的响应。 当我们有多个同时在线的请求时,我们必须说明他们以意外的顺序返回的情况。 想象一下,我们首先键入电脑 ,停止,请求熄灭,我们键入车 ,停止,请求熄灭。 现在我们有两个请求在飞行中。 不幸的是,携带计算机结果的请求在请求携带汽车结果后返回。
演示将包含两个文件: app.ts
和wikipedia-service.ts
。 但是在现实世界中,我们很可能会进一步分裂。
下面是基于Promise的实现,它不处理任何描述的边缘情况。
wikipedia-service.ts
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
服务,使用给定的search词对维基百科API进行GET
请求。 请注意,我们调用toPromise
以便从Observable<Response>
到Promise<Response>
。 最终以Promise<Array<string>>
作为search方法的返回types。
app.ts
// 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); } }
这里也不算什么惊喜。 我们注入我们的WikipediaService
并通过search方法向模板公开其function。 该模板只是绑定到search(term.value)
并调用search(term.value)
。
我们打开WikipediaService的search方法返回的Promise的结果,并将其作为一个简单的string数组展示给模板,以便我们可以通过*ngFor
循环并为我们build立一个列表。
请参阅Plunker上基于Promise的实现示例
观察者真正发光的地方
让我们改变我们的代码,不要每次按键都敲击端点,而只是在用户停止input400毫秒时才发送请求
为了揭示这样的超级权力,我们首先需要得到一个带有用户input的search词的Observable<string>
。我们可以利用Angular的formControl
指令来代替手动绑定到keyup事件。 要使用这个指令,我们首先需要将ReactiveFormsModule
导入到我们的应用程序模块中。
app.ts
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,并将其设置为名称“term”。
<input type="text" [formControl]="term"/>
在我们的组件中,我们从@angular/form
创buildFormControl
一个实例,并将其作为一个字段在组件的名称下暴露。
在幕后, 术语会自动公开一个Observable<string>
作为我们可以订阅的属性valueChanges
。 现在我们有一个Observable<string>
,克服用户input就像在我们的Observable
上调用debounceTime(400)
一样简单。 这将返回一个新的Observable<string>
,它只会在400ms内没有传入新的值时才会发出新的值。
export class App { items: Array<string>; term = new FormControl(); constructor(private wikipediaService: WikipediaService) { this.term.valueChanges .debounceTime(400) // wait for 400ms pause in events .distinctUntilChanged() // ignore if next search term is same as previous .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items)); } }
如果我们的应用程序已经显示search结果,那么发出另一个search字词的请求会浪费资源。 我们所要做的就是在我们调用debounceTime(400)
之后调用distinctUntilChanged
操作符,
请参阅Plunker上Observable实现的示例
为了处理无序的反应,请查看全文http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
至于我在Angular中使用Http,我同意在正常使用情况下使用Observable over Promise没有太大的区别。 这些优点在实践中没有任何真正的相关性。 希望未来能看到一些高级用例:)
学到更多
Promises和Observables都将帮助我们处理JavaScript中的asynchronousfunction 。 在大多数情况下,它们是非常相似的,但是,两者之间有一些区别,承诺是以asynchronous方式parsing的值,如http调用。 另一方面,观察者处理asynchronous事件的顺序。 主要区别如下:
诺言:
- 有一条pipe道
- 通常只用于asynchronous数据返回
- 不容易取消
观察到:
- 是可以取消的
- 是可以回溯的,如重试和重试时
- 在多个pipe道中stream数据
- 像地图,filter等类似数组的操作
- 可以从其他来源如事件创build
- 他们是function,可以在以后订阅
另外,我在下面为您创build了graphics图像,以便直观地显示差异:
承诺
- 定义:帮助您asynchronous运行函数,并在执行时使用它们的返回值(或exception),但仅使用一次 。
- 不懒
- 不可取消。 两个可能的决定是
- 拒绝
- 解决
- 不能重试 (Promises应该访问返回promise的原始函数以获得重试能力,这是一个不好的做法)
观测
- 定义:帮助您asynchronous运行函数,并在执行时以连续的顺序( 多次 )使用它们的返回值。
- 默认情况下,它是Lazy,因为它在时间推进时发出值。
- 有很多简化编码工作的操作员。
-
一个操作员重试可以用来在需要时重试,也可以根据某些条件重试重试观察值。
注意 : RxMarbles.com提供了一系列操作符及其交互图表
答案中缺lessObservables的一个缺点。 承诺允许使用ES7的asynchronous/等待function。 有了它们,你可以编写asynchronous代码,就好像它是一个同步函数调用一样,所以你不需要callback了。 Observables这样做的唯一可能性就是将它们转换为Promises。 但是当你将它们转换为Promises时,你只能再次得到一个返回值:
async function getData(){ const data = await observable.first().toPromise(); //do stuff with 'data' (no callback function needed) }
进一步阅读: 如何在Rx Observable上“等待”?
我刚才谈到了一个问题,Promise是最好的解决scheme,我在这里分享给大家,如果有任何人在这个问题上有用(这正是我之前寻找的答案):
在Angular2项目中,我有一个服务需要一些参数并返回一个值列表来填充表单上的下拉菜单。 当表单组件初始化时,我需要用不同的参数多次调用同一个服务来定义多个不同的下拉菜单,但是如果我只是排队所有的variables来调用服务,只有最后一个成功,其余的错误出。 从数据库获取的服务一次只能处理一个请求。
成功填充所有下拉菜单variables的唯一方法是调用服务,以防止在最后一个请求完成之前处理新的请求,而Promise / .then机制很好地解决了这个问题。
fetchValueList(listCode): Promise<any> { return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode) .map(response => response.json()) .toPromise(); } initializeDropDowns() { this.fetchValueList('First-Val-List') .then(data => { this.firstValList = data; return this.fetchValueList('Second-Val-List') }).then(data => { this.secondValList = data; return this.fetchValueList('Third-Val-List') }).then(data => { this.thirdValList = data; }) }
我在组件中定义了函数,然后在ngOnInit中调用了initializeDropDowns()。
fetchValueList函数返回Promise,所以第一次调用传递第一个listCode,当Promiseparsing时,返回值在.then块的datavariables中,我们可以把它赋给this.firstValListvariables。 由于函数已经返回了数据,我们知道服务已经完成,并且使用第二个listCode再次调用是安全的,返回值在下一个.then块的数据variables中,并且将其赋值给this.secondValListvariables。
我们可以根据需要链接多次,以填充所有variables,在最后一个代码块中,我们简单地省略了返回语句,块终止。
这是一个非常具体的用例,我们有一个单独的服务需要在组件初始化的时候被多次调用,并且服务必须完成它的获取并返回一个值,然后才能被再次调用,但在这种情况下, Promise / .then方法是理想的。
我相信所有其他的答案应该清除你的疑惑。 尽pipe如此,我只是想补充一点,observable是基于函数式编程的,我发现它非常有用,比如map,flatmap,reduce,zip等。 特别是当它取决于API请求时,networking的一致性是一个残酷的改进。
我强烈推荐这个文档 ,因为它是reactiveX的官方文档,我觉得它是最清楚的。
如果你想进入观察,我会build议这第三部分: http ://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
虽然它的意思是RxJava,但概念是一样的,并且很好地解释了它。 在reactiveX文档中,您具有每个函数的等价性。 你必须寻找RxJS。
我希望这有助于,只是尝试在这里贡献。 🙂
诺言:
- 提供单一的未来价值;
- 不懒;
- 不可取消;
观察到:
- 随着时间的推移发射多个值;
- 懒;
- 撤销;
- 支持地图,过滤,减less和类似的操作
如果您愿意,可以在Angular中调用HTTP时使用promise而不是observables。
尽pipe这个答案很晚,但我总结了下面的差异,
观察到:
- Observable只是一个接受
an observer
并返回一个function Observer: an object with next, error.
的function Observer: an object with next, error.
- Observer允许
subscribe/unsubscribe
其数据stream,向观察者发送下一个值,notify
观察者有关errors
并通知观察者stream completion
- Observer提供了一个
function to handle next value
,错误和stream结束(ui事件,http响应,带有networking套接字的数据)。 - 随着时间的推移使用
multiple values
- 可以
cancel-able/retry-able
,支持map,filter,reduce
等操作。 - 创build一个Observable可以是 –
Observable.create()
– 返回可以调用方法的Observer Observable.from()
–Observer Observable.from()
– 转换一个数组或者迭代到 –Observable Observable.fromEvent()
– 将一个事件转换成Observable –Observable.fromPromise()
– 将Promise转换为Observable –Observable.range()
– 返回指定范围内的整数序列
承诺 :
-
一个承诺代表将来要完成的任务;
-
承诺
resolved by a value
; -
承诺被例外拒绝;
-
不可
cancellable
,并返回a single value
-
一个承诺揭露一个function
(then)
然后返回一个新的
promise
;– 允许根据
state
执行attachment
;–
handlers
guaranteed
执行order attached
;