Promise vs Observable
有人能解释一下Angular的Promise
和Observable
之间的区别吗?
每个例子都有助于理解这两种情况。 我们可以在哪种情况下使用每种情况?
诺言
Promise
在异步操作完成或失败时处理单个事件 。
注意:有Promise
库支持取消,但ES6 Promise
目前还没有。
可观察
Observable
就像一个Stream
(在很多语言中),并允许传递零个或多个事件,其中为每个事件调用回调。
通常Observable
比Promise
更Promise
因为它提供了Promise
等功能。 使用Observable
,如果要处理0,1个或多个事件,则无关紧要。 您可以在每种情况下使用相同的API。
Observable
也有优于Promise
的优势可取消 。 如果不再需要向服务器发送HTTP请求或其他昂贵的异步操作的结果,则Observable
的Subscription
允许取消订阅,而Promise
最终将调用成功或失败的回调,即使您没有需要通知或其提供的结果。
Observable提供像map
, forEach
, reduce
等操作符 ,类似于数组
还有像retry()
或replay()
等强大的操作符,这些操作符通常非常方便。
公司承诺:
观测:
Promises
和Observables
为我们提供了抽象,帮助我们处理应用程序的异步性。 @Günter和@Relu明确指出了它们之间的区别。
由于代码片段胜过千言万语,请仔细阅读下面的示例,以更轻松地理解它们。
感谢@Christoph Burgdorf提供的精彩文章
Angular使用Rx.js Observable而不是承诺处理HTTP。
假设你正在建立一个搜索功能 ,当你输入时应该立即显示你的结果。 听起来很熟悉,但这项任务有很多挑战。
HTTP
请求的风暴来填充它们。 基本上,我们只想在用户停止输入而不是每次按键时击中它。 该演示将包含两个文件: 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
服务,以使用给定的搜索词对维基百科API进行GET
请求。 请注意,我们调用toPromise
以便从Observable<Response>
到Promise<Response>
。 最终以Promise<Array<string>>
作为我们搜索方法的返回类型。
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
并通过搜索方法向模板公开其功能。 模板只是结合KEYUP并调用search(term.value)
我们解开了Promise的结果,即WikipediaService的搜索方法返回并将其作为简单的字符串数组展示给模板,以便我们可以通过*ngFor
循环并为我们建立一个列表。
请参阅Plunker上基于Promise的实现示例
观察者真正发光的地方
让我们更改我们的代码,使其不用每次击键都敲击端点,而是只在用户停止输入400毫秒时才发送请求
为了揭示这样的超级权力,我们首先需要得到一个带有用户输入的搜索词的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
创建FormControl
一个实例,并将其作为组件名称下的字段公开。
在幕后, 术语会自动公开一个Observable<string>
作为我们可以订阅的属性valueChanges
。 现在我们有一个Observable<string>
,克服用户输入就像在我们的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));
}
}
如果我们的应用已经显示搜索结果,则发送另一个搜索字词的请求会浪费资源。 我们所要做的就是在我们调用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没有太大的区别。 在实践中,这些优势都没有真正相关。 希望我可以在未来看到一些高级用例:)
学到更多
下一篇: How do I access previous promise results in a .then() chain?