有人可以解释 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 Observables 而不是 promises 来处理 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
服务,以针对具有给定搜索词的Wikipedia 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
循环*ngFor
并为我们构建一个列表。
Observables真正发光的地方
让我们改变我们的代码,不要在每次击键时敲击端点,而只是在用户停止键入400 ms时才发送请求
为了揭示这样的超能力,我们首先需要获得一个带有用户输入的搜索词的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
实例,并将其作为我们组件上名称 term 下的字段公开。
在幕后, term 会自动将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
操作符
要处理无序响应,请查看完整的文章http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
至于我在 Angular 中使用 Http,我同意在正常使用情况下使用 Observable 而不是 Promise 没有太大区别。在实践中,这些优点都没有真正相关。希望将来可以看到一些高级用例:)
学到更多