Promise
Angular和Angular有什么区别Observable
?
每个例子都有助于理解这两种情况。我们可以在什么情况下使用每种情况?
Promise
Angular和Angular有什么区别Observable
?
每个例子都有助于理解这两种情况。我们可以在什么情况下使用每种情况?
承诺
A在异步操作完成或失败时Promise
处理单个事件。
注意:那里Promise
有支持取消的库,但 ES6Promise
到目前为止还没有。
可观察的
AnObservable
就像 a Stream
(在许多语言中)并允许传递零个或多个事件,其中为每个事件调用回调。
通常Observable
是首选,Promise
因为它提供了Promise
更多的功能。如果您想处理 0、1 或多个事件,Observable
这并不重要。您可以在每种情况下使用相同的 API。
Observable
还有一个优势Promise
就是可以取消。如果不再需要对服务器的 HTTP 请求或其他一些昂贵的异步操作的结果,则Subscription
允许Observable
取消订阅,而Promise
即使您不需要通知,最终也会调用成功或失败回调或它提供的结果。
虽然 aPromise
立即启动,但Observable
仅当您订阅它时才会启动。这就是为什么 Observable 被称为惰性的原因。
Observable 提供类似于数组的运算符,如map
, forEach
, , ...reduce
还有一些功能强大的运算符,例如retry()
, or replay()
, ... 通常非常方便。
rxjs 附带的运算符列表
延迟执行允许在通过订阅执行 observable 之前建立一系列运算符,以进行更具声明性的编程。
两者都Promises
为Observables
我们提供了抽象,帮助我们处理应用程序的异步特性。Günter和@Relu清楚地指出了它们之间的区别。
由于代码片段值一千字,让我们通过下面的示例更容易理解它们。
感谢@Christoph Burgdorf的精彩文章
Angular 使用 Rx.js Observables 而不是 Promise 来处理 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请求。请注意,我们调用是为了从 a到 a 。最终以 a作为我们搜索方法的返回类型。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上基于 Promise 的实现示例
Observables真正闪耀的地方
让我们更改我们的代码,不要在每次击键时敲击端点,而是仅在用户停止输入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"/>
在我们的组件中,我们创建了一个FormControl
from的实例,@angular/form
并将其公开为我们组件上名为 term 的字段。
在幕后,term自动公开了一个我们可以订阅的Observable<string>
as 属性。valueChanges
现在我们有了一个Observable<string>
,克服用户输入就像调用debounceTime(400)
我们的Observable
. 这将返回一个Observable<string>
新值,仅在 400 毫秒内没有新值时才会发出新值。
export class App {
items: Array<string>;
term = new FormControl();
constructor(private wikipediaService: WikipediaService) {
this.term.valueChanges
.debounceTime(400) // wait for 400 ms 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上的Observable实现示例
对于无序响应的处理,请查看完整文章 http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
就我在 Angular 中使用 HTTP 而言,我同意在正常用例中使用 Observable over Promise 并没有太大区别。在实践中,这些优点都不是真正相关的。我希望将来能看到一些高级用例:)
学到更多
Promises和Observables都将帮助我们使用 JavaScript 中的异步功能。在许多情况下,它们非常相似,但是两者之间也存在一些差异,promise 是以asynchronous
HTTP 调用之类的方式解析的值。另一方面,可观察对象处理一系列异步事件。它们之间的主要区别如下:
承诺:
可观察的:
此外,我在下面为您创建了图形图像,以直观地显示差异:
答案中缺少 Observables 的一个缺点。Promise 允许使用 ES7 的 async/await 函数。使用它们,您可以编写异步代码,就像它是一个同步函数调用一样,因此您不再需要回调。Observables 这样做的唯一可能性是将它们转换为 Promise。但是当你将它们转换为 Promises 时,你只能再有一个返回值:
async function getData(){
const data = await observable.first().toPromise();
//do stuff with 'data' (no callback function needed)
}
进一步阅读:如何在 Rx Observable 上“等待”?
承诺
可观察的
注意: **RxMarbles.com上提供了运算符列表及其交互式图表**
Promises 和 Observables 都只处理异步调用。
以下是它们之间的区别:
可观察的
承诺
一次只发出一个值
调用不带 .then 和 .catch 的服务
无法取消
不提供任何运算符
我总结了以下差异,
可观察的:
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()
- 将数组或迭代转换为 - Observable Observable.fromEvent()
- 将事件转换为 Observable - Observable.fromPromise()
- 将 Promise 转换为 Observable - Observable.range()
- 返回指定范围内的整数序列承诺:
承诺代表将在未来完成的任务;
承诺变成了resolved by a value
;
Promise 被异常拒绝;
不是cancellable
,它会返回a single value
一个promise暴露一个函数(then)
- 然后返回一个新的promise
;
- 允许attachment
基于
state
;
-handlers
将guaranteed
在执行order attached
;
我相信所有其他答案都应该消除您的疑虑。尽管如此,我只想补充一点,observables 是基于函数式编程的,我发现它附带的函数非常有用,例如 map、flatmap、reduce、zip。Web 实现的一致性,尤其是当它依赖于 API 请求时,这是一个残酷的改进。
我强烈推荐这个文档,因为它是 reactiveX 的官方文档,我发现它是最清楚的。
如果你想进入 observables,我建议你这篇由 3 部分组成的帖子: http ://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
虽然它是为 RxJava 设计的,但概念是相同的,而且解释得很好。在 reactiveX 文档中,您有每个函数的等价物。你必须寻找 RxJS。
我刚刚处理了一个问题,其中 Promises 是最好的解决方案,如果有用的话,我将在这里分享给任何偶然发现这个问题的人(这正是我之前正在寻找的答案):
在 Angular2 项目中,我有一个服务,它接受一些参数并返回一个值列表来填充表单上的下拉菜单。当表单组件初始化时,我需要使用不同的参数多次调用同一个服务来定义许多不同的下拉菜单,但是如果我只是将所有变量排队来调用服务,只有最后一个成功,其余的错误出去。从数据库中获取的服务一次只能处理一个请求。
成功填充所有下拉菜单变量的唯一方法是调用服务,以防止在最后一个请求完成之前处理新请求,并且 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,当 Promise 解析时,返回值在 .then 块中的数据变量中,我们可以将它分配给 this.firstValList 变量。由于函数返回了数据,我们知道服务已经完成,可以安全地使用第二个 listCode 再次调用,返回值在下一个 .then 块的数据变量中,我们将它分配给 this.secondValList 变量。
我们可以根据需要将其链接多次以填充所有变量,并且在最后一个代码块上,我们只需省略 return 语句并且块终止。
这是一个非常具体的用例,我们有一个服务需要在组件初始化时被多次调用,并且服务必须完成其获取并返回一个值才能再次调用它,但在这种情况下, Promise / .then 方法非常理想。
您始终可以使用可观察对象来处理异步行为,因为可观察对象具有承诺提供的所有功能(+额外)。但是,有时不需要 Observables 提供的这种额外功能。然后导入一个库以供它使用它们将是额外的开销。
当您有一个要处理其结果的异步操作时,请使用 Promise。例如:
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 会执行一些代码,它要么解决要么拒绝。如果调用了resolve 或reject,则promise 从挂起状态变为已解决或拒绝状态。当承诺状态被解决时,该then()
方法被调用。当 promise 状态被拒绝时,该catch()
方法被调用。
当需要处理一段时间内的(数据)流时,请使用 Observables 。流是随着时间的推移而变得可用的数据元素序列。流的示例是:
在 Observable 本身中指定下一个事件发生的时间、错误发生的时间或 Observable 的完成时间。然后我们可以订阅这个 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 被订阅时,它会调用传入订阅的相应回调。
假设你想去海滩。您必须根据天气做出决定。你有三种方式:
你向外看,看到雨滴,所以你改变了主意。这是一个同步操作。你停止了你正在做的事情,去外面检查,得到结果,然后又回到你正在做的事情上。
你请你旁边的兄弟检查今天的天气状况。当他检查天气时,你仍然继续做你正在做的事情。这是一个异步操作。你给你的兄弟一个任务,等待承诺得到解决。在这种情况下,您会收到一个回复,在您收到回复后,您将不再收到任何更新。
这一次,您打开收音机并收听 24/7 全天候广播天气状况的天气频道。在这种情况下,响应是持续进行的,而不是得到一个响应。这个响应就像一个subscription
对一个observable
。observable 是“天气”,subscription 是“让您保持最新状态的无线电信号”。只要您的收音机打开,您就会获得所有可用的更新。在您关闭收音机之前,您不会错过任何信息。当您关闭收音机时,这意味着“您已取消订阅”。
Promise - 提供单一的未来值。不懒惰。不可取消。它会拒绝或解决。
Observable - 提供多个未来值。懒惰的。可取消。它提供了其他方法,例如map、filter和reduce。
两者都用于处理异步代码。
请查找承诺示例。Promise 构造函数传递一个解析引用函数,该函数将在完成某个异步任务后以某个值调用时被调用。
const promise = new Promise(resolve => {
setTimeout(() => {
resolve("Hello from a Promise!");
}, 2000);
});
promise.then(value => console.log(value));
现在可以观察到的例子。在这里,我们还将一个函数传递给 observable - 一个处理异步任务的观察者。与 promise 中的 resolve 不同,它具有以下方法并订阅代替 then。
所以两者都处理异步任务。现在让我们看看区别。
const observable = new Observable(observer => {
setTimeout(() => {
observer.next('Hello from a Observable!');
}, 2000);
});
observable.subscribe(value => console.log(value));
承诺
可观察的
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
简短的回答:
可观察的更好。它具有所有Promises功能以及额外的功能。
长答案:
承诺:
可观察的:
当异步活动完成或失败时,Promise 会发出单个事件。
Observable 类似于 Stream(在许多语言中),并且允许传递至少零个或多个事件,其中每个事件都需要回调。
通常 Observable 比 Promise 更受欢迎,因为它提供了 Promise 的亮点等等。使用 Observable,您是否需要处理 0、1 或各种事件都无关紧要。您可以对每种情况使用类似的 API。
Promise: promise 发出单个值
例如:
const numberPromise = new Promise((resolve) => {
resolve(5);
resolve(10);
});
numberPromise.then(value => console.log(value));
// still prints only 5
Observable: 在一段时间内发出多个值
例如:
const numberObservable = new Observable((observer) => {
observer.next(5);
observer.next(10);
});
numberObservable.subscribe(value => console.log(value));
// prints 5 and 10
我们可以将 observable 想象成一个流,它在一段时间内发出多个值,并且为每个发出的项目调用相同的回调函数,因此使用 observable 我们可以使用相同的 API 来处理异步数据。该数据是在一段时间内作为单个值还是多个值传输的。
承诺:
可观察的:
以下是 Promise 和 Observable 的一些重要区别。
承诺
可观察的
为了更好地理解,请参阅https://stackblitz.com/edit/observable-vs-promises
承诺:
异步事件处理程序 - Promise 对象表示异步操作的最终完成(或失败)及其结果值。
语法: new Promise(executor);
例如:
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()。
可观察的:
Observables 是多个值随时间推移的惰性集合。这确实是异步操作的好方法。它可以使用具有跨平台支持的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等。
虽然Günter Zöchbauer 的回答总体上很好,但我认为它并没有强调在处理 Angular 组件时,您几乎总是希望使用 Observable,因为它支持取消。Promise 不能被取消,即使你的组件被销毁也会解决。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();
});
}
如果你的组件在 Promise 被解决之前被销毁,当 Promise 被解决时你会得到一个attempt to use destroyed view
错误。
或者,如果您将 observables 与takeUntil模式一起使用,那么一旦您的组件被销毁,订阅就会被取消。
这是一个人为的例子,但是为被破坏的组件执行代码可能会导致错误。
在第一次阅读教程和文档时,我遇到的并不明显的是多播的想法。
确保您知道默认情况下,多个订阅将触发 Observable 中的多个执行。多个订阅单个 HTTP 调用 Observable 将触发多个相同的 HTTP 调用,除非您.share()
(启用多播)。
Promise 迫使你一次处理一件事,解包它的数据,处理异常,对诸如 async/await 之类的很酷的东西提供语言支持,否则它是非常简单的。
Observable 有很多花里胡哨,但你需要了解你正在使用的力量,否则它可能会被滥用。
我看到很多人使用 Observable 是“可取消”的论点,但让 Promise “可取消”是相当微不足道的
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
Promise : 是一个 ES6 特性,它处理异步代码,它在创建时立即执行,当时只能发出一个值并且不可取消。随着现代应用程序和功能需求的复杂性,有必要实现复杂的代码,如果我们要同时执行许多 Promise,或者在执行前进行过滤或进行一些转换:
myPromise.then((resolvedValue) => {
console.log(resolvedValue);
}, (error) => {
console.log(error);
});
Observable:是 Rxjs 库提供的一个对象,它帮助我们在 JavaScript 应用程序中使用响应式编程,它提供链接和订阅来处理具有可取消优势的复杂应用程序,同时提供许多值。此外,我们可以从应用其他运算符的链接中受益,例如retry()
, map()
, filter()
,switchMap()
等,这有助于处理复杂的用例和繁重的用户界面。
即时搜索示例:
search(terms: Observable<string>) {
return terms.pipe(
debounceTime(400),
distinctUntilChanged(),
switchMap((term) => this.searchEntries(term))
);
}
并行的许多 APIS 调用示例:
let character = this.http.get('https://jsonplaceholder.typicode.com/todos');
let characterHomeworld = this.http.get(
'https://jsonplaceholder.typicode.com/posts'
);
forkJoin([character, characterHomeworld]).subscribe((results) => {
console.log('result °', results[0]);
console.log('result 1', results[1]);
});
Promise 仅针对单个值或解析。Observables 是数据流。
Observables 可以被取消,但 Promise 不能被取消。
至少对我来说,最不为人所知的是:
如果您想详细了解它,我在这个答案之后写了一篇博客文章 - JavaScript 中 Observables 和 Promises 之间的 4 个区别
另一个区别:全球与进口
Promise 是一个标准的内置对象,你可以直接使用它。在此处检查浏览器支持。
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) });
JavaScript 的Observable响应式扩展需要在使用前安装和导入RxJS
import { Observable } from 'rxjs';
当异步操作完成或失败时,Promise 会处理单个事件。
Promise 是在应用程序中自动执行的,而 observables 是惰性的。所以我们必须订阅 observables 才能返回数据。
我们不能取消订阅承诺。与可以取消订阅的 Observable 相比,它们每次都会执行。
关于这个话题已经有很多答案了,所以我不会添加多余的答案。
但是对于刚开始学习Observable / Angular并想知道将哪个与Promise进行比较的人,我建议您保留所有内容 Observable 并将项目中所有现有的 Promise 转换为 Observable。
仅仅是因为 Angular 框架本身和它的社区都在使用 Observable。因此,当您集成框架服务或第三方模块并将所有内容链接在一起时,这将是有益的。
当然,没有任何意见在所有情况下都是 100% 正确的,但至少我认为 98% 的情况下,对于在 Angular 框架中实施的常规商业项目,Observable 是正确的方法。
即使你在你的简单爱好项目的起点不喜欢它,你很快就会意识到你在 Angular 中与之交互的几乎所有组件,并且大多数对 Angular 友好的第三方框架都使用 Observables,然后你' 最终会不断地将你的 Promise 转换为 Observable 以便与他们交流。
这些组件包括但不限于:HttpClient、Form builder、Angular material modules/dialogs、Ngrx store/effects 和 ngx-bootstrap。
事实上,过去两年我处理的来自 Angular 生态系统的唯一 Promise 是APP_INITIALIZER
.