乐闻世界logo
搜索文章和话题

What is the difference between Promises and Observables?

9 个月前提问
5 个月前修改
浏览次数142

6个答案

1
2
3
4
5
6

PromiseObservable 在异步编程中都很常见,尤其是在 JavaScript 和基于 JavaScript 的框架(如 Angular)中。尽管它们处理异步操作,但它们的工作方式和功能有所不同。以下是它们之间的一些主要区别:

1. 单值 vs 多值

  • Promise:
    • Promise 代表一个异步操作的最终结果。它只处理单个异步操作并返回一个单一的值。
  • Observable:
    • Observable 可以发出多个值,是一个流式数据集合。它可以发出零个到多个值,并且可以随着时间无限地进行。

2. 惰性 vs 主动

  • Promise:
    • Promises 是不惰性的,这意味着一旦创建,它们立即执行。
  • Observable:
    • Observables 是惰性的。Observable 执行(称为订阅)只有在有订阅者时才会开始。

3. 取消

  • Promise:
    • 一旦启动,Promise 就无法取消。它要么解析一个值,要么拒绝一个错误。
  • Observable:
    • Observables 可以被取消。订阅者可以取消订阅,这样操作就可以停止执行。

4. 操作符

  • Promise:
    • Promise 在本身具有有限的操作方法,例如 .then(), .catch(), 和 .finally()
  • Observable:
    • Observable 支持广泛的操作符,如 map(), filter(), concat(), flatMap(), 等等,可以使用这些操作符来处理流中的数据。

5. 错误处理

  • Promise:
    • 在 Promise 中,错误通过拒绝来处理,可以用 .catch() 方法来捕获。
  • Observable:
    • 在 Observable 中,错误可以在流的任何部分被捕获,并可以使用特殊的错误处理操作符。

6. 使用场景

  • Promise:
    • Promises 通常用于单一异步任务,当你对一次性事件感兴趣时使用。
  • Observable:
    • Observables 更适合处理时间序列中的数据、用户输入、HTTP请求等,尤其是当涉及多个值或你想要处理如取消或连续的数据流时。

总的来说,Promise 更适合简单的异步转换,而 Observable 提供了更强大的控制,适用于复杂的数据流和异步事件的处理。

2024年6月29日 12:07 回复

承诺

当异步操作完成或失败时,APromise处理单个事件。

注意:有些Promise库支持取消,但 ES6Promise到目前为止还不支持。

可观察的

AnObservable就像 a Stream(在许多语言中)一样,允许您传递零个或多个事件,其中为每个事件调用回调。

通常Observable更受青睐,Promise因为它提供了以下功能Promise以及更多功能。有了Observable它,无论您想处理 0 个、1 个还是多个事件都没有关系。您可以在每种情况下使用相同的 API。

Observable``Promise还具有可取消优势。如果不再需要对服务器的 HTTP 请求或其他一些昂贵的异步操作的结果, anSubscription允许Observable您取消订阅,而 aPromise最终会调用成功或失败的回调,即使您不需要通知或其提供的结果不再。

a 会Promise立即启动,而 aObservable仅在您订阅后才会启动。这就是 Observables 被称为惰性的原因。

Observable 提供类似于数组的运算符,如map, forEach, , ...reduce

还有一些强大的运算符,例如retry(), 或replay(), ... 通常非常方便。 rxjs 附带的运算符列表

延迟执行允许您在通过订阅执行可观察量之前构建运算符链,以进行更具声明性的编程。

2024年6月29日 12:07 回复

PromisesObservables为我们提供了抽象,帮助我们处理应用程序的异步特性。Günter和 @Relu清楚地指出了它们之间的区别。

由于代码片段相当于一千个单词,让我们通过下面的示例来更容易地理解它们。

感谢@Christoph Burgdorf 的精彩文章


Angular 使用 Rx.js Observables 而不是 Promise 来处理 HTTP。

假设您正在构建一个搜索功能,该功能应在您键入时立即显示结果。这听起来很熟悉,但这项任务会带来很多挑战。

  • 我们不想每次用户按键时都访问服务器端点。它应该用大量的HTTP请求淹没它们。基本上,我们只想在用户停止打字时点击它,而不是每次击键时点击它。
  • 不要为后续请求使用相同的查询参数来访问搜索端点。
  • 处理无序响应。当我们同时处理多个请求时,我们必须考虑它们以意外顺序返回的情况。想象一下,我们首先输入Computer,停止,一个请求发出,我们输入car,停止,一个请求发出。现在我们有两个请求正在处理中。不幸的是,携带计算机结果的请求在携带汽车结果的请求之后返回。

该演示仅包含两个文件:app.tswikipedia-service.ts. 不过,在现实世界中,我们很可能会进一步拆分事物。


下面是一个基于 Promise 的实现,它不处理任何所描述的边缘情况。

wikipedia-service.ts

shell
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]); } }

我们正在注入服务,以使用给定的搜索词向维基百科 APIJsonp发出GET请求。请注意,我们调用是为了从 an到 a 。最终以 a作为我们搜索方法的返回类型。toPromise``Observable<Response>``Promise<Response>``Promise<Array<string>>

app.ts

shell
// 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

shell
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”。

shell
<input type="text" [formControl]="term"/>

FormControl在我们的组件中,我们创建一个from实例@angular/form,并将其公开为组件上名称 term 下的字段。

在幕后,term自动公开一个我们可以订阅的Observable<string>as 属性。valueChanges现在我们有了一个Observable<string>,克服用户输入就像调用debounceTime(400)我们的Observable. 这将返回一个新值Observable<string>,只有在 400 毫秒内没有出现新值时才会发出新值。

shell
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)

请参阅PlunkerObservable实现的示例

对于处理无序响应,请查看完整文章 http://blog.thoughtram.io/angular/2016/01/06/take-advantage-of-observables-in-angular2.html

就我在 Angular 中使用 HTTP 而言,我同意在正常用例中使用 Observable 与 Promise 没有太大区别。这些优点在实践中都没有真正相关。我希望将来能看到一些高级用例:)


了解更多

2024年6月29日 12:07 回复

PromisesObservables都将帮助我们使用JavaScript 中的异步功能。它们在许多情况下非常相似,但是,两者之间仍然存在一些差异,promise 是将以asynchronousHTTP 调用等方式解析的值。另一方面,可观察量处理一系列异步事件。它们之间的主要区别如下:

承诺:

  • 拥有一条管道
  • 通常仅与异步数据返回一起使用
  • 不容易取消

可观察到:

  • 可以取消
  • 本质上是可重试的,例如 retry 和 retryWhen
  • 在多个管道中传输数据
  • 具有类似数组的操作,如映射、过滤器等
  • 可以从事件等其他来源创建
  • 它们是函数,可以稍后订阅

另外,我在下面为您创建了图形图像,以直观地显示差异:

承诺和观察图像

2024年6月29日 12:07 回复

答案中缺少 Observables 的一个缺点。Promise 允许使用 ES7 async/await 函数。使用它们,您可以编写异步代码,就像同步函数调用一样,因此您不再需要回调。Observables 做到这一点的唯一可能性是将它们转换为 Promise。但是当你将它们转换为 Promise 时,你只能再有一个返回值:

shell
async function getData(){ const data = await observable.first().toPromise(); //do stuff with 'data' (no callback function needed) }

进一步阅读:如何在 Rx Observable 上“await”?

2024年6月29日 12:07 回复

承诺

  1. 定义:帮助您异步运行函数,并使用它们的返回值(或异常),但在执行时使用一次。
  2. 不懒惰
  3. 不可取消(有 Promise 库支持取消,但 ES6 Promise 到目前为止还不支持)。两个可能的决定是
    • 拒绝
    • 解决
  4. 无法重试(Promise 应该有权访问返回 Promise 的原始函数以具有重试功能,这是一个不好的做法)

观测值

  1. 定义:帮助您异步运行函数,并在执行时连续(多次)使用它们的返回值。
  2. 默认情况下,它是_惰性的_,因为它会随着时间的推移而发出值。
  3. 有很多运算符,简化了编码工作。
  4. 可以使用一个运算符重试来在需要时重试,如果我们需要根据某些条件重试可观察对象,也可以使用retryWhen 。

注意:操作员列表及其交互图可在**RxMarbles.com **上找到

2024年6月29日 12:07 回复

你的答案