有人可以解释Angular中Promise
和Observable
之间的区别吗?
每个例子都有助于理解这两种情况。 在什么情况下我们可以使用每个案例?
答案 0 :(得分:1303)
<强>无极强>
当异步操作完成或失败时,Promise
处理单个事件。
注意:有Promise
个库支持取消,但到目前为止ES6 Promise
还没有。
<强>可观察强>
Observable
就像 Stream
(在许多语言中),允许传递零个或多个事件,为每个事件调用回调。
Observable
通常优先于Promise
,因为它提供Promise
等功能。使用Observable
如果您想要处理0,1或多个事件并不重要。您可以在每种情况下使用相同的API。
Observable
还有优于Promise
可取消的优势。如果不再需要向服务器发送HTTP请求的结果或其他昂贵的异步操作,Subscription
的{{1}}允许取消订阅,而Observable
即使您不再需要通知或其提供的结果,也会最终调用成功或失败的回调。
Observable提供运算符,例如Promise
,map
,forEach
,...类似于数组
还有强大的运算符,例如reduce
或retry()
,......通常非常方便。
答案 1 :(得分:279)
Promises
和Observables
都为我们提供了抽象,帮助我们处理应用程序的异步特性。 @Günter和@Relu清楚地指出了它们之间的区别。
由于代码段值得千言万语,让我们通过下面的示例更容易理解它们。
感谢@Christoph Burgdorf的精彩article
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)
。
我们打开WikipediaService的搜索方法返回的 Promise 的结果,并将其作为一个简单的字符串数组暴露给模板,以便我们可以*ngFor
循环它并为我们建立一个清单。
请参阅Plunker
上基于承诺的实施的示例Observables 真正发光的地方
让我们更改我们的代码,以便在每次击键时都不会敲定端点,而只是在用户停止输入 400 ms 时发送请求
为了揭示这样的超能力,我们首先需要得到一个Observable<string>
,其中包含用户输入的搜索词。而不是手动绑定到keyup事件,我们可以利用Angular的formControl
指示。要使用此指令,我们首先需要将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"/>
在我们的组件中,我们从FormControl
创建@angular/form
的实例,并将其作为我们组件上名称术语下的字段公开。
在幕后,术语会自动将Observable<string>
公开为我们可以订阅的属性valueChanges
。现在我们有Observable<string>
,克服用户输入就像调用debounceTime(400)
上的Observable
一样简单。这将返回一个新的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));
}
}
发送我们的应用已经显示结果的搜索字词的另一个请求将浪费资源。我们要实现所需行为所需要做的就是在调用distinctUntilChanged
之后立即调用debounceTime(400)
运算符
请参阅Plunker
上的可观察实施示例要处理无序响应,请查看完整文章 http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
就我在Angular中使用Http而言,我同意在正常使用情况下使用Observable而不是Promise没有太大区别。在实践中,这些优点都没有真正相关。希望将来可以看到一些高级用例:)
了解详情
答案 2 :(得分:56)
<强>承诺强>
<强>观测量强>
一个运算符重试可用于在需要时重试,如果我们需要根据某些条件重试observable retryWhen 可以使用。< / p>
注意:可在RxMarbles.com
答案 3 :(得分:52)
答案中缺少Observables的一个缺点。 Promise允许使用ES7 async / await函数。有了它们,您可以编写异步代码,就像同步函数调用一样,因此您不再需要回调。 Observables执行此操作的唯一可能性是将它们转换为Promises。但是当你将它们转换为Promises时,你只能再次获得一个返回值:
async function getData(){
const data = await observable.first().toPromise();
//do stuff with 'data' (no callback function needed)
}
答案 4 :(得分:29)
promises和Observable都在处理上面的异步调用 图像为主要区别。
可观察
承诺
它一次仅发出一个单值
lt不使用.then和.catch
无法取消
它不提供任何运营商
答案 5 :(得分:19)
即使这个答案迟了,我总结了下面的差异,
<强>可观察强>
function
, an observer
并返回 function Observer: an object with next, error.
subscribe/unsubscribe
到其数据流,发出
观察者的下一个值 notify
关于 errors
的观察者
告知观察者 stream completion
function to handle next value
,错误和
流的结尾(ui事件,http响应,带有Web套接字的数据)。multiple values
cancel-able/retry-able
,支持 map,filter,reduce
等运营商。Observable.create()
- 返回可以调用方法的Observable
- Observer Observable.from()
- 将数组或iterable转换为
- Observable Observable.fromEvent()
- 将事件转换为Observable
- Observable.fromPromise()
- 将Promise转换为Observable
- Observable.range()
- 返回指定范围内的整数序列<强>无极强>:
承诺代表着将来完成的任务;
承诺变为 resolved by a value
;
承诺被例外拒绝;
不 cancellable
并返回 a single value
承诺公开函数 (then)
- 然后返回新的 promise
;
- 允许 attachment
的基础上执行
的 state
强>;
- handlers
guaranteed
可在 order attached
中执行;
答案 6 :(得分:17)
我相信所有其他答案都应该清除你的怀疑。 不过,我只是想补充说,observables是基于函数式编程的,我发现它附带的函数非常有用,如map,flatmap,reduce,zip。 Web实现的一致性尤其在依赖于API请求时是一种残酷的改进。
我强烈推荐this documentation,因为它是reactiveX的官方文档,我发现它是最清晰的。
如果你想进入可观察者,我会建议这个由3部分组成的帖子: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
虽然它适用于RxJava,但概念是相同的,并且它的解释非常好。在reactiveX文档中,您具有每个函数的等价性。你必须寻找RxJS。
答案 7 :(得分:16)
我刚刚处理过一个Promise是最佳解决方案的问题,我在这里分享这个问题,因为任何人在这个问题很有用的情况下绊倒这个问题(这正是答案)我之前正在寻找):
在Angular2项目中,我有一个服务,它接受一些参数并返回一个值列表来填充表单上的下拉菜单。当表单组件初始化时,我需要使用不同的参数多次调用相同的服务来定义许多不同的下拉菜单,但是如果我只是将所有变量排队以调用服务,则只有最后一个成功并且其余错误出。从数据库中提取的服务一次只能处理一个请求。
成功填充所有下拉菜单变量的唯一方法是以阻止在上一个请求完成之前处理新请求的方式调用服务,并且Promise / .then机制很好地解决了问题。 / p>
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,当Promise解析时,返回值位于.then块中的数据变量中,我们可以将它分配给this.firstValList变量。当函数返回数据时,我们知道服务已经完成,并且使用第二个listCode再次调用是安全的,返回值在下一个.then块的数据变量中,我们将其分配给它。 secondValList变量。
我们可以根据需要多次链接这个以填充所有变量,在最后一个代码块中我们只是省略return语句并且块终止。
这是一个非常具体的用例,我们有一个单独的服务,需要在组件初始化时多次调用,并且服务必须完成其获取并返回一个值才能再次调用,但是在这种情况下,Promise / .then方法是理想的。
答案 8 :(得分:12)
答案 9 :(得分:9)
您可以始终使用可观察对象来处理异步行为,因为可观察对象具有promise所提供的所有功能(+额外)。但是,有时不需要Observables提供的此额外功能。然后,要为其导入一个库以使用它们将是额外的开销。
当您要执行结果的单个异步操作时,请使用诺言。例如:
var promise = new Promise((resolve, reject) => {
// do something once, possibly async
// code inside the Promise constructor callback is getting executed synchronously
if (/* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
//after the promise is resolved or rejected we can call .then or .catch method on it
promise.then((val) => console.log(val)) // logs the resolve argument
.catch((val) => console.log(val)); // logs the reject argument
因此,promise会在解决或拒绝的地方执行一些代码。如果称为解决或拒绝,则承诺将从待处理状态变为已解决或已拒绝状态。解析承诺状态后,将调用then()
方法。当承诺状态被拒绝时,将调用catch()
方法。
在需要处理随时间流逝的(数据)流时,请使用Observables。流是一系列数据元素,它们随时间可用而变得可用。流的示例是:
在发生下一个事件,发生错误或完成时,在Observable中指定。然后,我们可以订阅这个可观察的对象,这将激活它,并且在这个订阅中,我们可以传递3个回调(不一定总是传递所有回调)。要成功执行一次回调,就错误执行一次回调,并为完成执行一次回调。例如:
const observable = Rx.Observable.create(observer => {
// create a single value and complete
observer.onNext(1);
observer.onCompleted();
});
source.subscribe(
x => console.log('onNext: %s', x), // success callback
e => console.log('onError: %s', e), // error callback
() => console.log('onCompleted') // completion callback
);
// first we log: onNext: 1
// then we log: onCompleted
创建可观察对象时,它需要一个回调函数,该函数将观察者作为参数。然后,您可以在此观察者上呼叫onNext
,onCompleted
,onError
。然后,在订阅Observable时,它将调用传递到订阅中的相应回调。
答案 10 :(得分:7)
承诺 - 提供单一的未来价值。不懒惰。不可取消。它会拒绝或解决。
可观察 - 提供多种未来价值。懒惰。可以取消。它提供其他方法实时地图,过滤,减少。
答案 11 :(得分:4)
Observables和Promises都提供了使用JavaScript中的 async 活动的方法。尽管基于单个异步事件(http请求)的完成承诺拒绝/解决,但是Observable可以根据订阅它们的观察者不断发出状态更改。
它们之间的一个基本区别是,可观察对象提供了取消请求和重新发送新请求的方法。如所保证的那样,不允许使用此功能。
此外,Promise发出一个值,而Observable发出多个值。因此,在处理HTTP请求时,Promise可以管理同一请求的单个响应,但是如果对同一请求有多个响应,那么我们必须使用Observable。
答案 12 :(得分:4)
Promise:是 ES6 的一项功能,用于处理在创建时立即执行的异步代码,该代码当时只能发出单个值且不可取消,具有现代应用程序和功能需要,如果我们要同时执行多个promise,或者在执行前过滤或者做一些转换,就需要实现复杂的代码:
myPromise.then((resolvedValue) => {
console.log(resolvedValue);
}, (error) => {
console.log(error);
});
Observable: 是 Rxjs 库中提供的一个对象,它帮助我们在 js 应用程序中使用响应式编程,它提供链接和订阅来处理具有可取消优势的复杂应用程序,提供了许多值的同时,此外,我们还可以应用其他运算符的链接,例如 retry()
、map()
、{{ 1}} 、filter()
等...有助于处理复杂的用例和繁重的用户界面
即时搜索示例:
switchMap()
并行调用多个 APIS 的示例:
search(terms: Observable<string>) {
return terms.pipe(
debounceTime(400),
distinctUntilChanged(),
switchMap((term) => this.searchEntries(term))
);
}
答案 13 :(得分:3)
当异步活动完成或失败时,Promise会发出一个事件。
Observable类似于Stream(在许多语言中),并且允许传递至少零个或多个事件,每个事件都需要回调。
与Promise相比,“ Foquently Observable”更受青睐,因为它提供了Promise的亮点以及更多内容。使用Observable,您是否需要处理0、1或各种事件都没有关系。您可以针对每种情况使用类似的API。
承诺: 许诺发出单个值
例如:
const numberPromise = new Promise((resolve) => {
resolve(5);
resolve(10);
});
numberPromise.then(value => console.log(value));
// still prints only 5
可观察的: 在一段时间内发出多个值
例如:
const numberObservable = new Observable((observer) => {
observer.next(5);
observer.next(10);
});
numberObservable.subscribe(value => console.log(value));
// prints 5 and 10
我们可以认为一个可观察对象就像一个流,该流在一段时间内发出多个值,并且对于每个发出的项都调用相同的回调函数,因此对于可观察对象,我们可以使用相同的API来处理异步数据。该数据是在一段时间内作为单个值还是多个值传输的。
承诺:
可观察:
答案 14 :(得分:2)
以下是Promise和Observable中的一些重要差异。
承诺
可观察
要更好地理解,请参阅https://stackblitz.com/edit/observable-vs-promises
答案 15 :(得分:2)
Promise和Observables均可帮助我们处理异步 操作。当这些异步时,他们可以调用某些回调 操作完成。
Angular使用来自RxJS的Observables代替了处理HTTP的承诺
Below are some important differences in promises & Observables.
答案 16 :(得分:1)
还有一个区别:全球与进口
Promise 是一个 Standard built-in object,你可以直接使用它,check the browser support here。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ready with out any installation');
}, 300);
});
myPromise
.then(value => { console.log(value) })
.catch(err => { console.log(err) });
Observable, Reactive Extensions for JavaScript 在使用前需要 RxJS installation & import
import { Observable } from 'rxjs';
答案 17 :(得分:1)
简而言之,承诺和可观察之间的主要区别如下:
更详细的信息,请参见this article
答案 18 :(得分:1)
承诺
当异步操作完成或失败时,Promise会处理一个事件。
注意:那里有Promise库支持取消,但是ES6 Promise到目前为止还不行。
可观察
一个Observable就像一个Stream(在许多语言中),并允许传递零个或多个事件,其中每个事件都需要回调。
答案 19 :(得分:1)
Promise仅关注单个值或解析,可观察对象是数据流。
可观察的事物可以被取消,但是诺言不能被取消。
我最不了解的是
答案 20 :(得分:1)
可观察到的东西常常被比作诺言。以下是一些主要区别:
可观察性是声明性的;直到订阅,计算才开始。承诺在创建后立即执行。这使可观察对象对于定义可在需要结果时运行的配方非常有用。
可观察对象提供许多值。承诺提供一个。这使得可观察变量对于随着时间的推移获取多个值很有用。
可观察对象区分链接和订阅。承诺只有.then()子句。这使得可观察对象对于创建供系统其他部分使用的复杂转换配方有用,而不会导致工作被执行。
Observables subscription()负责处理错误。诺言将错误推向孩子的诺言。这使得可观察对象对于集中式和可预测的错误处理很有用。
这是您在ANGULAR.IO文档中可能发现的最简单的区别。其余人给出的答案大多数都是正确的。
答案 21 :(得分:1)
const promise = new Promise(resolve => {
setTimeout(() => {
resolve("Hello from a Promise!");
}, 2000);
});
promise.then(value => console.log(value));
现在可观察的示例。在这里,我们还将一个函数传递给observable,一个观察者来处理异步任务。不同于在promise中解决问题,它具有以下方法并代替then进行订阅。
因此,两者都处理异步任务。现在,我们来看看区别。
const observable = new Observable(observer => {
setTimeout(() => {
observer.next('Hello from a Observable!');
}, 2000);
});
observable.subscribe(value => console.log(value));
承诺
可观察
答案 22 :(得分:1)
我看到很多人使用Observable是“ cancellable”的说法,但是将Promise设置为“ cancellable”是很简单的
function cancellablePromise(body) {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res; reject = rej;
body(resolve, reject)
})
promise.resolve = resolve;
promise.reject = reject;
return promise
}
// Example 1: Reject a promise prematurely
const p1 = cancellablePromise((resolve, reject) => {
setTimeout(() => resolve('10', 100))
})
p1.then(value => alert(value)).catch(err => console.error(err))
p1.reject(new Error('denied')) // expect an error in the console
// Example: Resolve a promise prematurely
const p2 = cancellablePromise((resolve, reject) => {
setTimeout(() => resolve('blop'), 100)
})
p2.then(value => alert(value)).catch(err => console.error(err))
p2.resolve(200) // expect an alert with 200
答案 23 :(得分:1)
承诺:
一个异步事件处理程序-Promise对象表示异步操作的最终完成(或失败)及其结果值。
语法:新的Promise(执行程序);
例如:
var promise_eg = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise_eg.then(function(value) {
console.log(value);
// expected output: "foo"
});
console.log(promise_eg);
关于承诺: 它只有一个管道,因此调用时只会返回一次值。 它的单向处理程序,因此一旦调用,您可能无法取消。 when()和 then()
可观察对象:
可观察值是随时间变化的多个值的惰性集合。对于异步操作而言,这确实是一个很好的方法。可以使用rxjs来完成,它具有跨平台支持,可以与angular / react等配合使用。
它的作用就像是班轮。可以是多管道。 因此,一旦定义,您就可以在许多地方订阅以获得返回结果。
语法: import * as Rx from "@reactivex/rxjs";
初始化:
Rx.Observable.fromEvent(button, "click"),
Rx.Subject()
等
要订阅:RxLogger.getInstance();
例如:
import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';
range(1, 200).pipe(
filter(x => x % 2 === 1),
map(x => x + x)
).subscribe(x => console.log(x));
由于它支持多管道,因此您可以在不同位置订阅结果, 它比承诺有很多可能性。
用法:
它有更多的可能性,例如map, filter, pipe, map, concatMap etc
答案 24 :(得分:1)
我对本教程的初读并不了解,而文档是多播的想法。
确保您知道默认情况下,多个订阅将在Observable中触发多个执行。单个HTTP调用的多个预订Observable将触发多个相同的HTTP调用,除非您.share()
(启用多播)。
一个诺言会迫使您一次处理一件事情,拆开其数据,处理异常,对异步/等待之类的很酷的事物提供语言支持,否则简直是准系统。
Observable具有很多风铃,但是您需要了解使用的功能,否则可能会被误用。
答案 25 :(得分:1)
虽然接受的答案通常是好的,但我认为它并不是强调在处理Angular Components时几乎总是要使用Observable,因为它支持取消。即使您的组件被销毁,也无法取消承诺并将解决。 Angular倾向于宽容,直到事实并非如此。
例如,对损坏的组件进行的任何手动更改检测都将导致异常:
ngOnInit() {
// promise api
this.service.getData().then(d => {
this.data = d;
this.changeDetectorRef.detectChanges();
});
// observable api
this.service.getData().pipe(takeUntil(this.unsubscribe)).subscribe((d) => {
this.data = d;
this.changeDetectorRef.detectChanges();
});
}
如果在解决诺言之前销毁了您的组件,则在解决诺言时会出现attempt to use destroyed view
错误。
或者,如果您使用具有takeUntil模式的可观察对象,那么一旦组件被破坏,订阅将被取消。
这是一个人为的示例,但是为被破坏的组件执行代码可能会导致bug。除非您出于某些原因实际上想要这样做:p
答案 26 :(得分:1)
简短答案:
可观察的是 更好 ,它具有所有承诺功能以及其他功能。
详细答案:
承诺:
可观察的
:答案 27 :(得分:0)
答案 28 :(得分:0)
答案 29 :(得分:0)
Promise发出一个值,而Observable发出多个值。因此,在处理HTTP请求时,Promise可以管理同一请求的单个响应,但是如果对同一请求有多个响应,那么我们必须使用Observable。是的,Observable可以为同一请求处理多个响应。
承诺
const promise = new Promise((data) =>
{ data(1);
data(2);
data(3); })
.then(element => console.log(‘Promise ‘ + element));
输出
Promise 1
可观察
const observable = new Observable((data) => {
data.next(1);
data.next(2);
data.next(3);
}).subscribe(element => console.log('Observable ' + element));
输出
Observable 1
Observable 2
Observable 3
答案 30 :(得分:0)
答案 31 :(得分:-3)
已经有很多关于此主题的答案,所以我不会添加多余的答案。
但是对于刚开始学习可观察 / Angular 的人,并想知道使用哪个人与 Promise 做比较,我建议您保留所有内容可观察的,并将项目中所有现有的Promises转换为可观察的。
仅因为Angular框架本身及其社区都使用Observable。因此,当您集成框架服务或第三方模块并将所有内容链接在一起时,这将是有益的。
尽管我感谢所有的反对意见,但我仍然坚持我的观点,除非有人发表适当的评论以列出一些可能仍对您的Angular项目有用的场景,以使用Promises over Observables。
当然,没有任何观点在所有情况下都是100%正确的,但是至少我认为在Angular框架中实施的常规商业项目中有98%的时间是可观察的。
即使您在简单的业余项目的开始就不喜欢它,您也会很快意识到与Angular进行交互的几乎所有组件,并且大多数Angular友好的3rd party框架都在使用Observables,然后您最终将不断地将Promise转换为Observable以便与他们进行交流。
这些组件包括但不限于:HttpClient,表单生成器,Angular材质模块/对话框,Ngrx存储/效果和ngx-bootstrap。
事实上,我在过去两年中处理的唯一来自Angular生态系统的承诺是APP_INITIALIZER
。