Promises和Observables有什么区别?


1395

PromiseObservableAngular有什么区别?

每个示例都将有助于理解这两种情况。在什么情况下我们可以使用每种情况?


23
我建议您阅读这篇文章;Angular2承诺与可观察
erolkaya84 '16


3
对于阅读此问答的任何人-作为维护者,演讲者和长期用户PoV涉及到两个领域的人,我鼓励您阅读有关Promise的RxJS官方文档和MDN文档。我个人发现这里的答案完全是误导性的和不正确的,并且相信它们虽然对试图帮助人们的良好意图非常有害。
本杰明·格林鲍姆

1
我建议您阅读这份有角度的官方文件angular.io/guide/comparing-observables
fgul

这就是为什么链接被视为不可接受的原因。
戴夫

Answers:


1547

诺言

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

注意:那里Promise有支持取消的库,但是ES6 Promise到目前为止还不支持。

可观察的

An Observable就像Stream(在许多语言中)一样,并且允许传递零个或多个事件,其中每个事件都将调用回调。

通常ObservablePromise它是首选,因为它具有Promise和的功能。有了Observable它,如果你想处理0,1或多个事件没有关系。在每种情况下,您都可以使用相同的API。

ObservablePromise对于取消也有优势。如果不再需要对服务器的HTTP请求或其他昂贵的异步操作的结果,则SubscriptionObservable可以取消订阅,而Promise最终会调用成功或失败的回调,即使您不需要通知也是如此或其提供的结果。

可观察到的提供运营商mapforEachreduce,...相似的阵列

还有一些功能强大的运算符,例如retry()replay(),...常常非常方便。


180
那么,是否有充分的理由在单个回调情况下使用Promise而不是Observable,还是应该在其中使用Observable,因为它们也可以那样工作?基本上,“可观察所有事物”是一种好习惯,还是Promise仍然占有一席之地?
Josh Werts

75
如果要使用反应式样式,只需在各处使用可观察对象。如果只有可观察物,就可以轻松撰写。如果将它们混合在一起,它就不再那么干净了。如果您不关心反应式,则可以将诺言用于单个事件,而不必关心事件流的可取消和可观察。
君特Zöchbauer

35
@GünterZöchbauer嘿-我没有反对Observables或函数式编程的观点。我只是简单地说,我相信主要通过NG2中的http进入Observable的人们没有任何真正的理由使用Promise上的Observables进行呼叫。通过使用诺言,他们不会失去任何实际的选择。debounce和retry运算符无关紧要-您可以使用ng-debounce来进行反跳,并且如果预期呼叫失败,通常来说,代码有问题。我唯一需要重试调用的时间是在查询不稳定的HVT第三方API时。
VSO

92
但是,请不要忘记Promiseasync/一起await使代码再次变得平坦!在大多数情况下,以及在不涉及火箭科学的项目中,都不需要使用不必要的复杂方法链来编写那些可怕的嵌套函数。今天,您可以将async/ await与转译器一起使用,例如TypeScript,并且无需任何rxjs样板即可编写实际的人类可读平面代码。rxjs在某些情况下,您有时可能仍需要,因为它确实提供了很多东西。
evilkos

15
这个答案是误导,可观察到的是不是像小溪它就像一个返回流功能
本杰明·格林鲍姆

333

双方PromisesObservables提供给我们,帮助我们应对抽象异步我们的应用程序的性质。@Günter和@Relu明确指出了它们之间的区别。

由于一个代码片段包含一千个单词,因此下面的示例使它们更容易理解。

感谢@Christoph Burgdorf的精彩文章


Angular使用Rx.js Observables代替了用于处理HTTP的Promise。

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

  • 我们不想每次用户按下一个键时都击中服务器端点,它应该向他们发出大量HTTP请求。基本上,我们只希望在用户停止键入后才敲击它,而不是每次击键都击中它。
  • 不要为后续请求使用具有相同查询参数的搜索端点。
  • 处理乱序响应。当我们同时有多个请求进行时,我们必须考虑到它们以意外顺序返回的情况。想象我们先键入计算机,停止,一个请求熄灭,我们键入汽车,停止,一个请求熄灭。现在我们正在进行两个请求。不幸的是,携带计算机结果的请求在携带汽车结果的请求之后又回来了。

该演示将仅包含两个文件:app.tswikipedia-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服务,以使用给定的搜索词GET针对Wikipedia API发出请求。请注意,我们toPromise为了从Observable<Response>到进行调用Promise<Response>。最终以a 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和call 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"/>

在我们的组件中,我们创建一个FormControlfrom 的实例,@angular/form并将其公开为一个字段,该字段位于我们组件上的名称术语下。

在幕后,term自动显示我们可以订阅的Observable<string>as属性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上的Observable实现示例

对于处理乱序的响应,请查看全文 http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

就我在Angular中使用Http而言,我同意在正常使用情况下使用Observable over Promise并没有太大区别。在实践中,这些优势都没有真正相关。希望以后能看到一些高级用例:)


学到更多


31
我不完全赞成将Http服务变成基于Observable的决定。我听到的每个解释都依赖于相同的示例:按词搜索。但是那是关于处理浏览器事件的。我想听听在处理异步http请求时应用它的好处。
Alex Pollan

1
为避免混合模式而做出的决定是偶然的吗?
Alex Pollan

6
@AlexPollan,实际上有一个很好的解释,表明在使用Ben Lesh的此播客中,http服务返回可观察的收益:devchat.tv/js-jabber/…。最终,主要的好处是您可以取消一个可观察的对象,并且上面链接中描述的用例(虽然有些许作弊)是,如果您调用多个api并且只关心第一个响应,那么无论您调用的api中的api首先返回给您,然后您可以取消对其他api的请求。
nikolasleblanc

2
@nikolasleblanc,我很确定您可以为此使用$ q.race()?
jameslouiz

2
@AlexPollan,优点是基于Observable的HTTP服务可以轻松取消正在进行的HTTP请求。通过在发出后续请求之前简单地取消订阅可观察到的HTTP,即可解决trungk18答案中的竞争条件。RXJS switchMap可用于其他可观察到的HTTP请求(例如valueChanges)。对于独立的HTTP可观察对象,您可以手动退订并重新订阅。
Stevethemacguy

234

双方承诺观测量将有助于我们的工作与异步功能在JavaScript中。它们在许多情况下非常相似,但是两者之间仍然存在一些差异,promise是可以asynchronous通过http调用等方式解析的值。另一方面,可观察对象处理一系列异步事件。它们之间的主要区别如下:

诺言:

  • 有一条管道
  • 通常只用于异步数据返回
  • 不容易取消

可观察的:

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

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

承诺和可观察的图像


4
承诺“不容易取消”,是否可以取消?
Pardeep Jain

10
是的,还有一种取消它们的方法...有些人使用蓝鸟或第三方库...也使用Angular中的Q库也有取消它的方法...但正如我说的不太方便
Alireza

例如,拥有一条管道有时会有优势。在APP_INITIALIZER中,如果您有多个管道,它有时可能永远无法完成或多次完成。
windmaomao

6
取消a Promise是思考承诺方式的错误方式。该Promise公司的IT负责只处理成功或失败的异步兼容的方式。如果你想取消您取消请求,而不是承诺的HTTP请求,并作出取消或者履行或拒绝承诺的结果。jsfiddle.net/greggman/ea0yhd4p
gman

2
@gman确实如此。Promise只是代表了一些未来价值。它并不能代表产生所述值的操作。您无法取消值。您无法重试值。这只是一个价值。它可能存在或可能不存在,并且可能永远不存在,因为发生了异常,仅此而已。
Yona Appletree,

75

承诺

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

可观察的

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

    注意:可以在RxMarbles.com上获得操作员列表及其交互图。


67

答案中缺少Observables的缺点。承诺允许使用ES7异步/等待功能。使用它们,您可以编写异步代码,就像执行同步函数调用一样,因此您不再需要回调。Observables这样做的唯一可能性是将它们转换为Promises。但是,当您将它们转换为Promises时,您只能再次获得一个返回值:

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

进一步阅读:如何在Rx Observable上等待?


21
也感到惊讶的是,为什么没人指出了Promises的杀手per-由于异步/等待,所以简单明了。我改用Promises只是为了能够编写平面代码。简单的业务逻辑和UI交互代码不应看起来像火箭科学,而且会被反应性扩展的嵌套地狱所污染。另外,异步/等待不仅在将来,您现在还可以使用编译器在公共生产应用中使用它。我使用TypeScript 2.3,它像一种真正的语言一样很棒。
evilkos

很好,但是以一种反应性的方式以及与RxOperators一起进行思考可能不是一个杀手级功能
JorgeTovar

37

Promises和Observables都仅处理异步调用。

这是它们之间的区别:

可观察的

  1. 在一段时间内发出多个值
  2. 在我们订阅Observable之前不被调用
  3. 可以通过使用unsubscribe()方法取消
  4. 提供映射,用于运算符的每次,过滤,缩小,重试和重试

诺言

  1. 一次仅发出一个值

  2. 调用没有.then和.catch的服务

  3. 无法取消

  4. 不提供任何运算符


2
您所说的诺言到底是什么意思,而可观察的则是多重?
Abel

2
一个承诺根本不产生价值-一个承诺随着时间的推移产生的价值。一个诺言会将该值多播到多个订户-持有诺言后,您就已经拥有了一个值。一个可观察对象就像一个函数,订阅它会调用该动作。
本杰明·格伦鲍姆

1
@BenjaminGruenbaum仍然我没有得到多个订阅者的意思,请您提供一个链接或示例。谢谢
Deepak Patidar '18

2
observable1.subscribe(subscriber1),observable1.subscribe(subscriber2)-这将多次调用该函数
本杰明·格伦鲍姆

2
编辑您的帖子,并显示实际文本而不是屏幕截图。其他人则无法从图像中复制和粘贴,也无法帮助您解决许多语法错误。有关详细信息,请参见此处。谢谢。

25

即使这个答案很晚,我还是总结了以下差异,

可观察的:

  1. 可观察的只是一个function需要an observer并返回一个 function Observer: an object with next, error.
  2. 观察者允许subscribe/unsubscribe对其数据流,观察者,notify观察者发出下一个值,errors并通知观察者stream completion
  3. 观察者提供function to handle next value,错误和流结束(ui事件,http响应,带有Web套接字的数据)。
  4. 与作品multiple values随着时间的推移
  5. 它是cancel-able/retry-able并支持诸如此类的运算符map,filter,reduce
  6. 创建一个Observable可以是-- Observable.create()返回可以调用方法的Observable-- Observer Observable.from()将数组或Iterable转换为Observable Observable.fromEvent()--将事件转换为Observable-- Observable.fromPromise()将Promise转换为Observable-- Observable.range()返回指定范围内的整数序列

承诺

  1. 许诺代表了一项将在未来完成的任务;

  2. 诺言成为resolved by a value;

  3. 承诺被例外拒绝;

  4. cancellable,它返回a single value

  5. 一个承诺公开功能 (then)

    -然后返回一个新的 promise

    的-允许attachment将基于 state

    - handlersguaranteed执行中order attached;


20

我刚刚处理了一个问题,其中“承诺”是最好的解决方案,我在这里与任何共享它的人分享,以免遇到任何有用的问题(这正是我之前所寻找的答案):

在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块中的data变量中,可以在其中将其分配给this.firstValList变量。由于函数已返回数据,因此我们知道服务已完成,可以安全地使用第二个listCode再次调用,返回值位于下一个.then块的data变量中,并将其分配给this.secondValList变量。

我们可以根据需要将其链接多次,以填充所有变量,并且在最后一个代码块中,我们只需省略return语句,然后该块终止。

这是一个非常特殊的用例,其中我们有一个服务需要在组件初始化时多次调用,并且该服务必须完成获取并返回值才能再次调用,但在这种情况下, Promise / .then方法是理想的。


3
对于(高阶)可观察变量,这当然也是可能的。例如,您可以用于scan()构建顺序可观察的流。但是,您的方法可能更明确,更容易理解。
lex82

1
您可以将“ then”替换为“ switchMap”,并执行与可观察对象完全相同的操作。
C. Hilarius博士

1
据我了解,switchMap的问题在于它将并行启动所有请求,等到它们全部返回,然后将值返回给调用函数,而在我的情况下,我只有一个服务器,并行调用多次(因为服务器会在收到新请求时丢弃未完成的请求),因此我必须确保对数据库服务的每次调用在开始新调用之前都已完成,并且Promise / then似乎是最好的,并且也许是解决这个问题的唯一方法。
史蒂芬·R·史密斯,

1
为什么不使用链接的mergeMap?据我了解您的代码,这段代码非常简单,可以完成您的示例。@ StephenR.Smith
Ore

1
@Ore可以添加一个代码示例来解决与另一个答案相同的问题吗?将是一个很好的参考,并且将来可能是一个很好的重构机会。要求是无论什么代码都不能并行调用后端服务,它必须调用,等待返回值并再次调用。
史蒂芬·R·史密斯,

20

我相信所有其他答案都应该清除您的疑问。尽管如此,我只是想补充一点,可观察对象是基于函数式编程的,并且我发现它所附带的函数非常有用,例如map,flatmap,reduce,zip。Web实现的一致性,特别是当它依赖于API请求时,是一种残酷的改进。

我强烈推荐该文档,因为它是reactX的正式文档,并且我认为它是最清晰的文档。

如果您想进入可观察的领域,我建议这篇文章分为三部分:http : //blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

尽管它是用于RxJava的,但概念是相同的,并且确实有很好的解释。在reactX文档中,您具有每个功能的等效项。您必须寻找RxJS。


18

诺言:

  • 提供单一的未来价值;
  • 不偷懒;
  • 无法取消;

可观察的:

  • 随着时间的推移发出多个值;
  • 懒;
  • 可取消;
  • 支持映射,过滤,缩小和类似运算符

如果愿意,可以在Angular中调用HTTP时使用Promise而不是Observables。


16

概述:

  • Promises和Observables都可以帮助我们处理异步操作。这些异步操作完成后,他们可以调用某些回调。
  • 一个Promise只能处理一个事件,Observables是随着时间流逝的事件流
  • 待处理的承诺无法取消
  • 可以使用运算符转换可观察到的数据

您可以始终使用可观察对象来处理异步行为,因为可观察对象具有诺言提供的所有功能(+额外)。但是,有时不需要Observables提供的此额外功能。然后,导入一个库以供使用它们将是额外的开销。

何时使用Promises:

当您有单个异步操作要处理结果时,请使用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会在其中解决或拒绝的地方执行一些代码。如果调用了解决或拒绝,则承诺将从待处理状态变为解决拒绝状态。解决承诺状态后,将then()调用该方法。当承诺状态被拒绝时,将catch()调用该方法。

何时使用Observables:

当您需要处理随时间流逝的(数据)流时,请使用Observables 。流是随时间推移变得可用的一系列数据元素。流的示例包括:

  1. 用户事件,例如单击或键入事件。用户随时间生成事件(数据)。
  2. Websocket,在客户端与服务器建立WebSocket连接后,它会随着时间推移推送数据。

当下一个事件发生,何时发生错误或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

创建可观察对象时,它需要一个回调函数,该函数提供观察者作为参数。在此观察,你可以接着调用onNextonCompletedonError。然后,当Observable订阅时,它将调用传递到订阅中的相应回调。


9

承诺-提供单一的未来价值。不偷懒。不可取消。它将拒绝或解决。

可观察-提供多个未来价值。懒。可以取消。它提供实时地图,过滤器,减少其他方法。


8

无极与可观察相似度优先

  1. 两者都用于处理异步代码。
  2. 请寻找承诺示例。Promise构造函数传递一个resolve引用函数,该函数将在完成某些异步任务后以某个值被调用时被调用。

const promise = new Promise(resolve => {
  setTimeout(() => {
    resolve("Hello from a Promise!");
  }, 2000);
});

promise.then(value => console.log(value));

  1. 现在可观察的例子。在这里,我们还将一个函数传递给observable,一个观察者来处理异步任务。与承诺中的解决方法不同,它具有以下方法,然后代替订阅。

  2. 因此,两者都处理异步任务。现在让我们看一下区别。


const observable = new Observable(observer => {
  setTimeout(() => {
    observer.next('Hello from a Observable!');
  }, 2000);
});

observable.subscribe(value => console.log(value));

承诺与可观察的差异

诺言

  1. 它解析或拒绝单个值,并且一次可以处理单个值异步任务。
  2. 一个诺言一旦解决了它完成的异步值,就不能再使用了,它只能一次使用,在这里就不够用了。
  3. 无法取消
  4. 不支持rxjs运算符。

可观察的

  1. 能够发出多个异步值。
  2. 用于处理事件或值流。考虑到您有一个由许多任务或值组成的数组,并且您希望每次将值插入到其中时都应自动处理它。每当您将值推入该数组时,其所有订阅者都会自动收到最新值。
  3. 可观察对象对于观察输入更改,重复间隔,向所有子组件的广播值,Web套接字推送通知等很有用。
  4. 可以随时使用取消订阅方法取消。
  5. 可以保证的最后一个好处是对rxjs运算符的支持。您有很多管道运算符,主要是映射,过滤,switchMap,combinateLatest等,用于在订阅之前转换可观察的数据。

在此处输入图片说明



6

Promises和Observables都可以帮助我们处理异步操作。这些异步操作完成后,他们可以调用某些回调。

Angular使用来自RxJS的Observables代替了处理HTTP的承诺

Below are some important differences in promises & Observables.

承诺与可观察指标之间的差异


1
列表数据似乎不正确,标题应互换
-Derrick.X

1
编辑您的信息,并将实际内容显示为文本而不是屏幕截图。其他人则无法从您的图像中复制和粘贴。有关详细信息,请参见此处。谢谢。

6

当异步活动完成或失败时,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来处理异步数据。该数据是在一段时间内作为单个值还是多个值传输的。

诺言:

  • 许诺不是偷懒
  • 承诺无法取消

可观察的:

  • 可观察的是懒惰。“可观察”很慢。在我们订阅它之前,它不会被调用。
  • 可以使用unsubscribe()方法取消Observable
  • 另外,Observable提供了许多强大的运算符,例如map,foreach,filter,reduce,retry,retryWhen等。

角度承诺与可观察值


5

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

3

以下是Promise和Observables的一些重要区别。

诺言

  • 仅发出一个值
  • 无法取消
  • 不可分享
  • 始终异步

可观察的

  • 发出多个值
  • 仅在调用或有人订阅时执行
  • 可以取消
  • 可以由多个订阅者共享和订阅该共享值。并且所有订户将在单个时间点执行。
  • 可能是异步的

为了更好地理解,请参阅https://stackblitz.com/edit/observable-vs-promises


3

我看到很多人使用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


2

简短答案:

可观察更好,它具有所有Promises功能以及其他功能。


长答案:

承诺:

  • 一次使用“一次返回数据”
  • 不取消
  • 一位听众
  • 没有套接字支持一个侦听器

可观察的:

  • 随着数据变化多次返回数据
  • 支持取消
  • 支持插座
  • 支持许多侦听器,并在数据更改时通知他们
  • 支持地图,过滤,缩小

我认为您不能说Observable在客观上更好。这里各种答案中都提到了Observables的缺点。对我而言突出的是Observable的复杂性,并且它们不能直接用于await / async。我个人觉得它们真的很难使用,因为您无法确定Observable在使用时的行为-您必须查看生成它的代码。有了Promise,您将始终准确地知道它们的工作方式。例如,有时订阅Observable具有副作用(例如,http请求),但有时则没有副作用。
Yona Appletree,

对于角度,这取决于您的情况。在大多数情况下,我们将使用服务和一些数据,这些数据会影响不同的位置,套接字,取消,地图,过滤和缩小。因此在那些情况下会更好,因为诺言不支持它们。再次取决于您的情况
Amr Ibrahim

2

虽然普遍接受的答案是好的,但我认为它并不强调在处理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模式的可观察对象,那么一旦组件被破坏,订阅将被取消。

这是一个人为的示例,但是为被破坏的组件执行代码可能会导致错误。除非您出于某种原因实际上想要这样做:p


2

初读本教程和文档时,我碰到的事情并没有多播的想法。

确保您知道默认情况下,多个订阅将在Observable中触发多个执行。单个HTTP调用的多个预订Observable会触发多个相同的HTTP调用,除非您.share()(启用多播)。

一个诺言会迫使您一次处理一件事情,拆开其数据,处理异常,对异步/等待之类的很酷的事物提供语言支持,否则就是准系统。

一个Observable有很多风吹草动,但是您需要了解使用的功能,否则它可能会被滥用。


2

诺言:

异步事件处理程序-Promise对象表示异步操作的最终完成(或失败)及其结果值。

语法: new 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);

在此处输入图片说明

关于Promise: 它只有一个管道,因此调用时仅返回一次值。它的单向处理程序,因此一旦调用,您可能无法取消。您可以在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


2

可观察的和承诺的基本区别是:

在此处输入图片说明


2
编辑您的信息,并将实际内容显示为文本而不是屏幕截图。其他人则无法从您的图像中复制和粘贴。有关详细信息,请参见此处。谢谢。

1

可观察的事物经常被与诺言相提并论。以下是一些主要区别:

观测值是声明性的;直到订阅,计算才开始。承诺在创建后立即执行。这使可观测对象对于定义可以在需要结果时运行的配方非常有用。

观察值提供许多值。承诺提供一个。这使得可观察变量对于随着时间的推移获取多个值很有用。

观察对象区分链接和订阅。承诺只有.then()子句。这使得可观察对象对于创建要由系统其他部分使用的复杂转换配方有用,而不会导致工作被执行。

Observables subscription()负责处理错误。诺言将错误推向孩子的诺言。这使得可观察对象对于集中式和可预测的错误处理很有用。

这是您在ANGULAR.IO文档中可能发现的最简单的区别。其余的答案在大多数地方都是正确的


1
  1. 承诺仅关注单个值或解析,可观察对象是数据流。

  2. 可观察对象可以被取消,但是诺言不能被取消。

我最不了解的是

  1. 承诺始终具有异步性质,但是可观察对象可以是同步的也可以是异步的。

0
  1. 承诺是渴望的,而可观察者是懒惰的,
  2. Promise始终是异步的,而Observable可以是同步或异步的,
  3. Promise可以提供一个值,而Observable是一个
    值流(从0到多个值),
  4. 您可以将RxJS运算符应用于Observable以获得新的定制流。

-1

Observables和Promises帮助我们使用JavaScript /打字稿中的异步功能。它们在许多情况下非常相似,但是它们之间仍然存在一些差异。

在此处输入图片说明


1
编辑您的帖子,并显示实际文本而不是屏幕截图。其他人则无法从您的图像中复制和粘贴。有关详细信息,请参见此处。谢谢。

除了不是代码而是简单的信息,所以我认为可以将其发布为图像
Alator

1
停止从Kudvenkat的youtube视频复制粘贴。拒绝我!:)
Pratik

-2

关于这个话题已经有很多答案,所以我不会添加多余的答案。

但是对于刚开始学习Observable / Angular并想与Promise进行比较的人来说,我建议您保持所有Observable并将项目中所有现有Promises转换为Observable。

仅仅是因为Angular框架本身及其社区都在使用Observable。因此,当您集成框架服务或第三方模块并将所有内容链接在一起时,这将是有益的。


虽然我很感谢所有的反对意见,但是我仍然坚持我的观点,除非有人发表适当的评论以列出一些可能仍在您的Angular项目中使用Promise over Observables的方案。

当然,在所有情况下都没有100%正确的意见,但至少我认为在Angular框架中实施常规商业项目的98%的时间中,Observable是正确的方法。

即使您在简单的业余项目的开始就不喜欢它,您也会很快意识到与Angular进行交互的几乎所有组件,并且大多数Angular友好的3rd party框架都在使用Observables,然后您将最终不断地将您的Promise转换为Observable以便与他们交流。

这些组件包括但不限于:HttpClient,表单构建器,Angular材质模块/对话框,Ngrx存储/效果和ngx-bootstrap。

实际上,我在过去两年中处理的唯一关于Angular生态系统的承诺是APP_INITIALIZER

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.