Promises和Observables有什么区别?

Roh*_*hit 1291 promise rxjs angular-promise angular angular-observable

有人可以解释Angular Promise和之间的区别Observable吗?

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

Gün*_*uer 1449

诺言

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

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

可观察

An Observable类似于Stream(在许多语言中)并允许传递零个或多个事件,其中为每个事件调用回调.

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

Observable也有优势Promise取消.如果不再需要一个HTTP请求到服务器或其他一些昂贵的异步操作的结果是,Subscription一个Observable允许取消订阅,而Promise最终将调用的成功或失败的回调,即使你不需要通知或者它提供的结果.

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

还有一些强大的运营商,比如retry(),或者replay()......通常非常方便.

  • 那么在单回调的情况下是否有充分的理由使用Promise而不是Observable,或者Observables是否也可以在那里使用,因为它们也可以这样工作?基本上,"观察所有事物"或Promise仍然有它的位置是一种好习惯吗? (172认同)
  • 但请不要忘记,"Promise"和"async"/"await"会让您的代码再次变平!在大多数情况下,以及不涉及火箭科学的项目中,没有必要用不必要的复杂方法链编写那些可怕的嵌套函数.今天你可以使用`async` /`await`和`,类似`TypeScript`,并编写实际的人类可读的扁平代码,而不需要任何`rxjs`样板.在某些情况下,你可能仍然需要`rxjs`,因为它确实提供了许多东西. (78认同)
  • 如果你想使用反应式,只需在任何地方使用observable.如果你有可观察的东西,你可以轻松编写.如果你混合它们就不再那么干净了.如果您不关心反应式风格,则可以将承诺用于您不关心可取消和可观察事件流的单个事件. (73认同)
  • @GünterZöchbauer嘿 - 我没有反对Observables或函数式编程的论据.我只是说我相信人们主要通过NG2中的http进入Observables没有任何理由使用Observables而不是Promises来进行调用.他们通过使用承诺失去了任何实际可行性 去抖和重试操作符是无关紧要的 - 你可以使用ng-debounce进行去抖动,如果预期调用失败,通常会出现代码问题.我需要处理重试呼叫的唯一一次是查询HVT的不稳定的第三方API. (35认同)
  • 这个答案具有误导性,一个可观察的_不像流一样,它就像一个返回stream_的函数. (14认同)
  • @VSO我同意 - 我可以看到Observable优于Promise的优点,但有时会有一个回调就是这样.在这种情况下,我认为Observable创建的代码有点难以理解,因此在这种情况下我只是toPromise().混合确实会伤害一致性.基本上,没有正确/错误的答案IMO. (5认同)
  • @evilkos 根据我的经验,使用 rxjs 时嵌套只会在做错时发生。如果做得对,您很少需要多于一层的缩进,因为管道是一个非常强大的概念。嵌套主要发生在您订阅所有内容而不是链接 observable 时。 (5认同)
  • 有关Observables / RxJs / Reactive Programming的良好介绍资源,请访问:https://gist.github.com/staltz/868e7e9bc2a7b8c1f754(“您已经缺少对Reactive编程的介绍”) (2认同)
  • @JoshWerts我在一两个星期前问了同样的问题.做了很多研究.就我而言,没有充分的理由使用Observables而不是Promises for http.在实践中,这些优点都没有真正相关.有了这个说,既然我理解了Observables,我就懒得写"toPromise()" (2认同)
  • 它们可以通过错误提前完成,但这不会取消操作。 (2认同)
  • 任何人都可以告诉我,取消`Observable`的能力是如何优于'Promises`的?当使用promises时,我可以链接它们并控制是否应该触发链中的下一个promise. (2认同)
  • 在等待异步调用完成时,“Promise”(ES6)无法被取消,而 Observable 却可以。这种取消可能会传播回异步结果的生产者,甚至可能停止昂贵的计算,而“Promise”仍然会执行昂贵的计算,即使接收者已经决定不再对结果感兴趣并且不会等等吧。 (2认同)
  • 在我的api调用返回单个事物(即JSON对象或对象数组)的情况下,我发现自己使用了"热"可观察对象.`供应商:Observable <any> = this.http.get(url).map(res => res.json()).publishLast().refCount();`在这种情况下使用Observable很酷的是你可以在多个地方订阅它,它不会重新查询.无论如何,只是使用Observables的一个原因. (2认同)
  • @Vivek或者您可以使用takeUntil,我发现它更简洁易用,但这取决于您使用的框架。在Angular中,您可以将其与ngOnDestroy结合使用。 (2认同)
  • 取消 Promise 是考虑 Promise 的错误方式。Promise 的责任只是以异步兼容的方式记录成功或失败。如果你想取消一个 http 请求,你取消请求,而不是承诺,并使取消的结果实现或拒绝承诺。https://jsfiddle.net/greggman/ea0yhd4p/ (2认同)
  • @PardeepJain感谢您指出。我尚未找到发表评论的方法。我只是喜欢这个答案变得如此流行,以至于有些人觉得值得窃取:D (2认同)
  • 我几年前开始使用 Promise 并习惯了它的模式,但后来它在 Angular 中默认为 Observable。这对我来说似乎没有什么区别,因为我不需要 Observable 的新功能。尽管您可以使用 toPomise() 函数隐藏对 Promise 的任何返回,但它非常方便。 (2认同)

tru*_*k18 310

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

由于代码片段胜过千言万语,让我们通过下面的示例更容易理解它们.

感谢@Christoph Burgdorf的精彩文章


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

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

  • 我们不希望每次用户按下某个键时都会点击服务器端点,它应该充满了一堆HTTP请求.基本上,我们只想在用户停止键入而不是每次按键时都点击它.
  • 对于后续请求,请勿使用相同的查询参数命中搜索端点.
  • 处理无序响应.当我们同时在飞行中有多个请求时,我们必须考虑他们以意想不到的顺序返回的情况.想象一下,我们先输入电脑,停止,请求消失,我们打,停止,请求消失.现在我们有2个飞行请求.不幸的是,带有计算机结果的请求在带有汽车结果的请求之后返回.

该演示将只包含两个文件: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]);
  }
}
Run Code Online (Sandbox Code Playgroud)

我们正在注入该Jsonp服务,以GET针对具有给定搜索词的Wikipedia API提出请求.请注意,我们打电话toPromise是为了从a Observable<Response>到a 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这里也没有什么惊喜.我们注入WikipediaService并通过搜索方法将其功能暴露给模板.模板只是绑定到keyup和调用search(term.value).

我们打开了Promise的结果,即WikipediaService的搜索方法返回并将其作为一个简单的字符串数组暴露给模板,以便我们可以*ngFor循环遍历它并为我们建立一个列表.

请参阅Plunker基于Promise的实现示例


观测量大放异彩

让我们改变我们的代码,不要在每次击键时敲击端点,而只是在用户停止键入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 {}
Run Code Online (Sandbox Code Playgroud)

导入后,我们可以在模板中使用formControl并将其设置为名称"term".

<input type="text" [formControl]="term"/>
Run Code Online (Sandbox Code Playgroud)

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

在幕后,术语会自动公开我们可以订阅的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));
  }
}
Run Code Online (Sandbox Code Playgroud)

发送我们的应用已经显示结果的搜索字词的另一个请求将浪费资源.我们所要做的就是distinctUntilChanged在我们调用之后立即调用操作符debounceTime(400)

请参阅Plunker上的Observable实现示例

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

至于我在Angular中使用Http,我同意在正常使用情况下使用Observable而不是Promise没有太大区别.在实践中,这些优点都没有真正相关.希望将来可以看到一些高级用例:)


学到更多

  • 我没有完全购买将Http服务转换为基于Observable的决定.我听到的每一个解释都依赖于同一个例子:按术语搜索.但那个是关于处理浏览器事件.我想知道在处理异步http请求时应用它有什么好处. (30认同)
  • @AlexPollan,实际上有一个很好的解释,http服务的好处是在Ben Lesh上播放这个播客的观察点:https://devchat.tv/js-jabber/jsj-248-reactive-programming-and-rxjs-with-奔故障.最终,主要的好处是你可以取消一个可观察的,以及上面链接中描述的用例 - 虽然有点人为 - 如果你呼唤多个apis并且只关心第一个响应,无论哪个您呼叫的api首先会回复给您,然后您可以取消对其他人的请求. (4认同)
  • @AlexPollan,优点是基于 Observable 的 HTTP 服务可以轻松取消传输中的 HTTP 请求。trungk18 的答案中的竞争条件可以通过在发出后续请求之前简单地取消订阅 HTTP observable 来解决。RXJS switchMap 可用于由另一个可观察对象(例如 valueChanges)触发的 HTTP 请求。对于独立的 HTTP 可观察量,您可以手动取消订阅和重新订阅。 (4认同)
  • @nikolasleblanc,我很确定你可以使用$ q.race()吗? (2认同)
  • 假设您输入 foo,停止,再输入一个 o,然后立即退格并返回到 foo。这应该只是一个带有 foo 一词的请求,而不是两个,即使我们在技术上在搜索框中包含 foo 后停止了两次。这就是distinctUntilChanged 所做的。您可以从 https://www.learnrxjs.io/operators/filtering/distinctuntilchanged.html 查看更多示例 (2认同)

Ali*_*eza 214

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

诺言:

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

观察到:

  • 是可以取消的
  • 当然可以重试,例如重试和重试
  • 在多个管道中传输数据
  • 具有类似于数组的操作,如map,filter等
  • 可以从事件等其他来源创建
  • 它们是函数,可以在以后订阅

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

承诺和观察者形象

  • 是的,还有一种方法可以取消它们......有些人使用蓝鸟或第三方库...在Angular中也使用Q库有取消它的方法......但正如我所说的不是很方便 (10认同)
  • @gman 没错。Promise 只是代表一些未来的 _value_。它_不_代表生成值_的_操作。您不能取消一个值。您不能重试一个值。这只是一个值。它可能会或可能不会_存在_,并且它可能_永远_不存在,因为发生了异常,但仅此而已。 (6认同)
  • 取消“承诺”是思考承诺的错误方式。“承诺”仅以异步兼容的方式处理成功或失败。 。https://jsfiddle.net/greggman/ea0yhd4p/ (4认同)
  • 承诺"不容易取消",是否有可能取消它们? (3认同)

Ara*_*ind 69

承诺

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

观测

  1. 定义:帮助您异步运行函数,并在执行时以连续的顺序(多次)使用它们的返回值.
  2. 默认情况下,它是Lazy,因为它会在时间进展时发出值.
  3. 有很多操作员可以简化编码工作.
  4. 当需要时,可以使用一个运算符重试来重试,如果我们需要根据某些条件重试observable retryWhen可以使用.

    注意:RxMarbles.com提供了运营商列表及其交互式图表


bes*_*ser 62

在答案中缺少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)
}
Run Code Online (Sandbox Code Playgroud)

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

  • 同样令人惊讶的是,为什么没有人指出这种杀手的杀手锏 - 简单和透明,这要归功于async/await.我转而使用Promises只是为了编写平面代码的能力.简单的业务逻辑和UI交互代码看起来不应该像火箭科学一样,并且被嵌套的反应性扩展所污染.此外,async/await不仅在将来,您现在可以使用转发器在公共生产应用程序中使用它.我使用TypeScript 2.3,它很棒,就像真正的语言一样. (20认同)
  • 这个答案肯定应该获得更多选票。Observables 非常强大,强大的功能带来了巨大的复杂性和回调地狱/回调金字塔末日类型的代码。在需要一些高级功能的地方使用 Observables。对于简单的情况,坚持使用 Promises 进行异步/等待,您的代码将变得更容易理解 10 倍。 (3认同)
  • 很好,但是以反应的方式思考并且全部使用 RxOperators 也许这不是一个杀手级功能 (2认同)
  • 我一直使用 Promise async/await,它真的很强大。它在使用真正的异步 JavaScript 引擎时提供了代码熟悉度和清晰度。相比之下,Observables 是同步的,它们在主执行堆栈中执行,而 Promise async/await 在引擎中使用 js 异步功能:事件循环、libuv、微任务队列等。使用 setTimeout() 使 Observables 异步很愚蠢,因为它是一个资源占用,您无法控制事件循环中的执行顺序。它使用事件循环的WebAPI部分,而微任务队列中的事件具有优先级 (2认同)

Yil*_*maz 44

假设您想去海滩。您必须根据天气做出决定。你有三种方法:

  1. 你向外望去,看到了雨滴,所以你改变了主意。这是一个同步操作。你停下手头的事情,去看看外面,得到结果,然后又回到你正在做的事情。

  2. 你让旁边的兄弟查看今天的天气状况。当他查看天气时,你仍然继续做你正在做的事情。这是一个异步操作。你给了你兄弟一个任务并等待承诺得到解决。在这种情况下,您将收到一个回复​​,在收到回复后,您将不再收到任何更新。

  3. 这次,您打开收音机并收听 24/7 广播天气状况的天气频道。在这种情况下,响应不是得到单一响应,而是持续进行。这个响应就像 asubscription到 an observable。可观察的是“天气”,订阅的是“让您了解最新情况的无线电信号”。只要您的收音机打开,您就会收到所有可用的更新。在关闭收音机之前,您不会错过任何信息。当您关闭收音机时,这意味着“您取消订阅”。


sud*_*nna 34

 承诺与可观察者

promises和Observable都只处理异步调用.找到上面的图像主要区别.

  • promise的确切含义只发出单个值,而observable则发出多个值 (2认同)
  • 承诺根本不会发出任何值 - 承诺_是一个随时间变化的值.承诺多播对多个订阅者有价值 - 一旦你履行了承诺,你已经拥有了一个价值.一个observable就像一个_function_,订阅它会调用该动作. (2认同)
  • observable1.subscribe(subscriber1),observable1.subscribe(subscriber2) - 这会多次调用_function_. (2认同)
  • 请** [编辑] **您的帖子,并显示实际文本而不是屏幕截图。其他人则无法从图像中复制和粘贴,也无法帮助您解决许多语法错误。[查看此处](https://meta.stackoverflow.com/a/285557/1402846)了解详情。谢谢。 (2认同)

Saj*_*ran 23

即使这个答案迟了,我总结了下面的差异,

观察到:

  1. Observable只是一个function接受an observer并返回一个 function Observer: an object with next, error.
  2. Observer允许subscribe/unsubscribe向其数据流发送下一个值给观察者,notify观察者errors并告知观察者stream completion
  3. Observer提供了一个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;


小智 19

我相信所有其他答案都应该清除你的疑虑.不过,我只是想补充说,observables是基于函数式编程的,我发现它附带的函数非常有用,如map,flatmap,reduce,zip.Web实现的一致性,特别是当它依赖于API请求时,是一种残酷的改进.

我强烈推荐这个文档,因为它是reactiveX的官方文档,我发现它是最明确的.

如果你想进入observables,我会建议这个由3部分组成的帖子:http: //blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

虽然它适用于RxJava,但概念是相同的,并且它的解释非常好.在reactiveX文档中,您具有每个函数的等价性.你必须寻找RxJS.


Ste*_*ith 18

我刚刚处理了一个问题,其中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;
          })  }
Run Code Online (Sandbox Code Playgroud)

我在组件中定义了函数,然后在ngOnInit中调用了initializeDropDowns().

fetchValueList函数返回一个Promise,因此第一个调用传递第一个listCode,当Promise解析时,返回值位于.then块中的数据变量中,我们可以将它分配给this.firstValList变量.当函数返回数据时,我们知道服务已经完成,并且使用第二个listCode再次调用是安全的,返回值在下一个.then块的数据变量中,我们将它分配给this.secondValList变量.

我们可以根据需要连接多次来填充所有变量,在最后一个代码块中我们只是省略return语句并且块终止.

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

  • 对于(高阶)可观察量,这当然也是可能的.例如,您可以使用`scan()`来构建顺序可观察数据流.但是,您的方法可能更明确,更容易理解. (3认同)
  • 您可以将“then”替换为“switchMap”,并使用 observables 执行完全相同的操作。 (2认同)

小智 16

诺言:

  • 提供单一的未来价值;
  • 不懒惰;
  • 不可取消;

观察到:

  • 随着时间的推移发出多个值;
  • 懒;
  • 撤销;
  • 支持map,filter,reduce和类似的运算符

如果您愿意,可以在Angular中调用HTTP时使用promises而不是observable.


小智 14

Promise 发出单个值,而 Observable 发出多个值。所以,在处理一个 HTTP 请求时,Promise 可以管理同一个请求的单个响应,但是如果同一个请求有多个响应,那么我们必须使用 Observable。是的,Observable 可以处理同一个请求的多个响应。

承诺

const promise = new Promise((data) =>
{ data(1);
  data(2);
  data(3); })
.then(element => console.log(‘Promise ‘ + element));
Run Code Online (Sandbox Code Playgroud)

输出

Promise 1
Run Code Online (Sandbox Code Playgroud)

可观察的

const observable = new Observable((data) => {
data.next(1);
data.next(2);
data.next(3);
}).subscribe(element => console.log('Observable ' + element));
Run Code Online (Sandbox Code Playgroud)

输出

Observable 1
Observable 2
Observable 3
Run Code Online (Sandbox Code Playgroud)


小智 13

Promise 与 Observable 相似性优先

  1. 两者都用于处理异步代码。

  2. 请寻找承诺的例子。承诺构造函数传递一个解析引用函数,该函数将在某些异步任务完成后被调用时调用。

    const promise = new Promise(resolve => {
      setTimeout(() => {
        resolve("Hello from a Promise!");
      }, 2000);
    });
    
    promise.then(value => console.log(value));
    
    Run Code Online (Sandbox Code Playgroud)
  3. 现在可以观察到的例子。在这里,我们还向 observable 传递了一个函数——一个处理异步任务的观察者。与promise 中的resolve 不同,它具有以下方法并订阅代替then。

  4. 所以两者都处理异步任务。现在让我们看看区别。

    const observable = new Observable(observer => {
      setTimeout(() => {
        observer.next('Hello from a Observable!');
      }, 2000);
    });
    
    observable.subscribe(value => console.log(value));
    
    Run Code Online (Sandbox Code Playgroud)

Promise 与 Observable 的区别

承诺

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

可观察的

  1. 能够发出多个异步值。

  2. 用于处理事件或值流。考虑到您有一个包含大量任务或值的数组,并且您希望每次将值插入其中时都应该自动处理。任何时候你将一个值推入这个数组,它的所有订阅者都会自动收到最新的值。

  3. Observables 可用于观察输入变化、重复间隔、向所有子组件广播值、Web 套接字推送通知等。

  4. 可以随时使用退订方法取消。

  5. 承诺的最后一个好部分是支持 rxjs 操作符。您有许多管道操作符,主要是 map、filter、switchMap、combineLatest 等,用于在订阅之前转换可观察数据。

    在此处输入图片说明


Wil*_*een 12

概述:

  • Promises和Observable都帮助我们处理异步操作.这些异步操作完成后,它们可以调用某些回调.
  • Promise只能处理一个事件,Observables用于随时间推移的事件流
  • 承诺一旦等待,就无法取消
  • Data Observables emit可以使用运算符进行转换

您始终可以使用observable来处理异步行为,因为observable具有promise提供的所有功能(+ extra).但是,有时候不需要Observables提供的这些额外功能.然后为它导入一个库以便使用它们将是额外的开销.

何时使用Promises:

当你有一个使用的承诺 ,其中要处理的结果异步操作.例如:

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
Run Code Online (Sandbox Code Playgroud)

因此,承诺会执行某些代码,无论是解析还是拒绝.如果调用resolve或reject,则promise将从挂起状态变为已解决拒绝状态.当解析promise状态时,then()调用该方法.当promise状态被拒绝时,catch()调用该方法.

何时使用Observables:

当存在需要处理的数据流(数据)时使用Observable .流是一系列数据元素,随着时间的推移可用.流的示例是:

  1. 用户事件,例如点击或键盘事件.用户随时间生成事件(数据).
  2. Websockets,在客户端与服务器建立websocket连接之后,它随时间推送数据.

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
Run Code Online (Sandbox Code Playgroud)

在创建一个observable时,它需要一个回调函数,它将一个观察者作为参数提供.在此观察,那么你可以打电话onNext,onCompleted,onError.然后,当Observable订阅它时,它将调用传递给订阅的相应回调.


DeC*_*DeC 10

当异步活动完成或失败时,Promise 会发出单个事件。

一个 Observable 就像一个 Stream(在许多语言中)并且允许传递至少零个或多个事件,其中每个事件都需要回调。

与 Promise 相比,Frequently 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
Run Code Online (Sandbox Code Playgroud)

Observable: 在一段时间内发出多个值

例如:

  const numberObservable = new Observable((observer) => {
        observer.next(5);
        observer.next(10);
    });

numberObservable.subscribe(value => console.log(value));
// prints 5 and 10
Run Code Online (Sandbox Code Playgroud)

我们可以将 observable 视为在一段时间内发出多个值的流,并且为每个发出的项目调用相同的回调函数,因此对于 observable,我们可以使用相同的 API 来处理异步数据。该数据是作为单个值还是在一段时间内作为多个值传输。

承诺:

  • 承诺不懒惰
  • Promise 无法取消

可观察:

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

Angular Promise 与 Observables


Sri*_*hna 9

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

Angular 使用来自 RxJS 的 Observables 而不是 promises 来处理 HTTP

Below are some important differences in promises & Observables.

Promises 和 Observables 的区别

  • 请**[编辑]**您的帖子,并将实际内容显示为文本而不是屏幕截图。其他人无法从您的图像中复制和粘贴。[参见此处](https://meta.stackoverflow.com/a/285557/1402846) 了解详情。谢谢你。 (2认同)

小智 8

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


Gaj*_*ngh 7

承诺 - 提供单一的未来价值.不懒惰.不可取消.它会拒绝或解决.

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


小智 7

在第一次阅读教程和文档时,我遇到的一些问题并不明显,那就是多播的概念。

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

Promise 迫使您一次处理一件事,解开其数据,处理异常,为 async/await 等很酷的事情提供语言支持,否则就非常简单了。

Observable 有很多花里胡哨的功能,但您需要了解您正在使用的功能,否则它可能会被滥用。


Bik*_*ram 6

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

承诺

  • 只发出一个值
  • 不可取消
  • 不可共享
  • 始终异步

可观察的

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

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


Moh*_*med 6

承诺:

异步事件处理程序 - 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);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

关于承诺:

它有一个管道,所以它在被调用时只会返回一次值。这是一种单向处理程序,因此一旦被调用,您可能无法取消。您可以使用的有用语法when()then()

观察值:

Observable 是随时间推移的多个值的惰性集合。这确实是异步操作的好方法。它可以使用具有跨平台支持的rxjs来完成,可以与 Angular/React 等一起使用。

它的作用类似于流线型,可以是多管道。所以一旦定义好,就可以在很多地方订阅获取返回结果。

语法: import * as Rx from "@reactivex/rxjs"; 初始化:

Rx.Observable.fromEvent(button, "click"),
Rx.Subject()
Run Code Online (Sandbox Code Playgroud)

等等。

认购: 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));
Run Code Online (Sandbox Code Playgroud)

由于它支持多管道,您可以在不同的位置订阅结果,

在此处输入图片说明

它有比承诺更多的可能性。

用法:

它有更多的可能性,比如mapfilterpipemapconcatMap等。


Amr*_*him 5

简短的回答:

观察到的更好的。它具有所有Promises功能以及额外的功能。


长答案:

承诺:

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

观察值:

  • 随着数据变化多次返回数据
  • 支持取消
  • 支持插座
  • 支持多个监听器并在数据发生变化时通知他们
  • 支持map、filter和reduce

  • 我不认为你可以说 Observables 客观上更好。这里的各种答案中指出了可观察量的许多缺点。对我来说最突出的是 Observable 的复杂性,并且它们不能直接与等待/异步一起工作。我个人发现它们真的很难使用,因为你无法确定 Observable 在使用时的行为——你必须查看生成它的代码。而有了 Promise,你就总是清楚地知道它们是如何工作的。例如,有时订阅 Observable 会产生副作用(例如 http 请求),但有时则不会。 (2认同)

shu*_*son 5

虽然Günter Zöchbauer 的回答总体上很好,但我认为它并没有强调在处理 Angular 组件时,您几乎总是想使用 Observable,因为它支持取消。Promises 不能被取消,即使你的组件被销毁也会解决。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();
  });
}
Run Code Online (Sandbox Code Playgroud)

如果你的组件在 promise 被解决之前被销毁,你会attempt to use destroyed view在 promise 被解决时得到一个错误。

或者,如果您将 observable 与takeUntil模式一起使用,那么一旦您的组件被销毁,订阅就会被取消。

这是一个有点人为的例子,但是为被销毁的组件执行代码可能会导致错误。


Bat*_*ler 5

我看到很多人使用 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
Run Code Online (Sandbox Code Playgroud)


Ahm*_*bai 5

承诺:是 ES6 的一项功能,用于处理异步代码,该代码在创建时立即执行,当时只能发出单个值并且不可取消。随着现代应用程序和功能需求的复杂性,如果我们要同时执行许多承诺,或者在执行之前进行过滤或进行一些转换,则有必要实现复杂的代码:

\n
myPromise.then((resolvedValue) => {\n    console.log(resolvedValue);\n}, (error) => {\n    console.log(error);\n});\n
Run Code Online (Sandbox Code Playgroud)\n

Observable:是 Rxjs 库提供的一个对象,可帮助我们在 JavaScript 应用程序中进行反应式编程,它提供链接和订阅来处理复杂的应用程序,具有可取消的优点,同时提供许多值。此外,我们可以从应用其他运算符(如retry()map()filter()switchMap()等)的链接中受益,这有助于处理复杂的用例和繁重的用户界面。

\n

即时搜索示例:

\n
search(terms: Observable<string>) {\n    return terms.pipe(\n      debounceTime(400),\n      distinctUntilChanged(),\n      switchMap((term) => this.searchEntries(term))\n    );\n  }\n
Run Code Online (Sandbox Code Playgroud)\n

并行调用多个 APIS 的示例:

\n
let character = this.http.get('https://jsonplaceholder.typicode.com/todos');\n    let characterHomeworld = this.http.get(\n      'https://jsonplaceholder.typicode.com/posts'\n    );\n\n    forkJoin([character, characterHomeworld]).subscribe((results) => {\n      console.log('result \xc2\xb0', results[0]);\n      console.log('result 1', results[1]);\n    });\n
Run Code Online (Sandbox Code Playgroud)\n


Anu*_*l S 5

另一个区别:全球与进口

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) });
Run Code Online (Sandbox Code Playgroud)

JavaScript 的可观察、反应式扩展需要RxJS 安装并在使用前导入

import { Observable } from 'rxjs';
Run Code Online (Sandbox Code Playgroud)