Promises 和 Observables 有啥区别?

Posted

技术标签:

【中文标题】Promises 和 Observables 有啥区别?【英文标题】:What is the difference between Promises and Observables?Promises 和 Observables 有什么区别? 【发布时间】:2016-09-18 19:09:30 【问题描述】:

Angular 中的PromiseObservable 有什么区别?

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

【问题讨论】:

我建议你阅读这篇文章; Angular2 promise vs observable 简单来说angular-2-training-book.rangle.io/handout/observables/… 致所有阅读此问答的人——作为维护者、演讲者和长期用户 PoV 参与这两个世界的人,我鼓励您阅读官方 RxJS 文档和关于 Promise 的 MDN 文档。 我个人认为这里的答案完全具有误导性和不正确性,并相信它们是非常有害的,尽管人们出于善意试图提供帮助。 我建议你阅读这个角度官方文档angular.io/guide/comparing-observables Promise 始终是异步的,而 Observable 可以是同步的也可以是异步的,Promise 可以提供单个值,而 Observable 是值流(从 0 到多个值),您可以将 RxJS 运算符应用于 Observable 以获得新的定制流 【参考方案1】:
    Promise 是急切的,而 Observable 是惰性的。 Promise 始终是异步的,而 Observable 可以是 同步或异步。 Promise 可以提供单个值,而 Observable 是一个 值流(从 0 到多个值)。 您可以将 RxJS 运算符应用于 Observable 以获得新的定制 流。

【讨论】:

【参考方案2】:

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

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

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

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

【讨论】:

很好的例子!让我一开始就明白了。谢谢:)【参考方案3】:

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

Promises 在应用程序中自动执行,而 observables 是惰性的。我们必须订阅 observables 才能返回数据。

我们不能取消订阅承诺。与可以取消订阅的 Observable 相比,它们每次都会执行。

【讨论】:

【参考方案4】:

简答:

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


长答案:

承诺:

一次性使用“返回数据一次” 不取消 一个听众 不支持套接字

可观察的:

随着数据变化多次返回数据 支持取消 支持套接字 支持多个监听器,并在数据变化时通知它们 支持 map、filter 和 reduce

【讨论】:

我认为你不能说 Observables 在客观上更好。此处的各种答案中指出了 Observables 的许多缺点。对我来说最突出的是 Observable 的复杂性,并且它们不能直接与 await/async 一起使用。我个人发现它们真的很难使用,因为在使用 Observable 时你无法确定它的行为——你必须查看生成它的代码。而通过 Promise,您始终可以确切地知道它们是如何工作的。例如,有时订阅 Observable 会产生副作用(例如 http 请求),但有时不会。 对于角度,这取决于您的情况。在大多数情况下,我们将使用服务和一些数据,这些数据会影响不同的地点、套接字、取消、映射、过滤和减少。因此,在这些情况下,作为不支持它们的承诺会更好。所以这又取决于你的情况【参考方案5】:

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

但是对于刚开始学习 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

【讨论】:

【参考方案6】:

虽然Günter Zöchbauer's answer 总体上很好,但我认为它并没有强调在处理 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 错误。

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

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

【讨论】:

【参考方案7】:

另一个区别:全球与进口

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

可观察,Reactive Extensions for javascript 需要RxJS installation & import 才能使用

import  Observable  from 'rxjs';

【讨论】:

【参考方案8】:

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

myPromise.then((resolvedValue) => 
    console.log(resolvedValue);
, (error) => 
    console.log(error);
);

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

即时搜索示例:

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

【讨论】:

【参考方案9】:

    Promise 仅针对单个值或解析。 Observables 是数据流。

    Observables 可以被取消,但 Promise 不能被取消。

至少对我来说,最不为人知的是:

    Promise 始终具有异步性质,但可观察对象既可以是同步的也可以是异步的。

如果您想详细了解它,我在此答案之后写了一篇博文 - The 4 differences between Observables and Promises in JavaScript

【讨论】:

【参考方案10】:

Promise 与 Observable 相似度优先

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

    请查看 promise 示例。 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 一旦解决了它完成的异步值,就不能再使用了。它只是一次性使用,在这里它就不足了。 不可取消 不支持操作符的 rxjs。

可观察

    能够发出多个异步值。

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

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

    可以随时使用取消订阅方法取消。

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

【讨论】:

【参考方案11】:

承诺:

异步事件处理程序 - 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));

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

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

用法:

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

【讨论】:

【参考方案12】:

第一次阅读教程和文档时,我遇到的一个问题是多播的想法。

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

Promise 会强制您一次处理一件事,解包其数据,处理异常,对异步/等待等很酷的事情提供语言支持,否则是非常简单的。

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

【讨论】:

【参考方案13】:

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

【讨论】:

edit您的帖子并显示实际文本而不是屏幕截图。其他人无法从您的图像中复制和粘贴。 See here 了解详情。谢谢。 除了不是代码而是普通信息,所以我认为可以将其作为图像发布【参考方案14】:

Promise - 提供单一的未来值。不懒惰。不可取消。它会拒绝或解决。

Observable - 提供多个未来值。懒惰的。可取消。它提供了其他方法,如 mapfilterreduce

【讨论】:

【参考方案15】:

我总结了以下差异,

可观察:

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

承诺

    承诺代表将在未来完成的任务;

    Promise 变成 resolved by a value;

    Promise 被异常拒绝;

    不是 cancellable 而是返回 a single value

    一个promise暴露一个函数(then)

    -然后返回一个新的promise

    -允许 attachment 将基于 state;

    -handlersguaranteedorder attached 中执行;

【讨论】:

【参考方案16】:

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

承诺:

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

可观察:

可以取消 本质上是可重试的,例如重试和重试时 在多个管道中流式传输数据 具有类似数组的操作,如 map、filter 等 可以从其他来源(如事件)创建 它们是函数,以后可以订阅

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

【讨论】:

承诺“不容易取消”,可以取消吗? 是的,也有一种方法可以取消它们...有些人使用蓝鸟或第三方库...也在 Angular 中使用 Q 库有一些方法可以取消它...但是作为我说不是很方便 取消Promise 是思考如何承诺的错误方式。 Promise 只负责以异步兼容的方式处理成功或失败。如果要取消 http 请求,则取消请求,而不是承诺,并使取消的结果履行或拒绝承诺. jsfiddle.net/greggman/ea0yhd4p @gman 没错。 Promise 只是代表一些未来的。它确实代表产生值的操作。您不能取消值。您不能重试一个值。这只是一个值。它可能存在,也可能不存在,因为发生了异常,但仅此而已。 @gman 很好地解释了 Promise 基础。我认为人们错误地认为 Promise 应该做一些他们不打算做的事情,实际上,他们非常擅长做他们应该做的事情。【参考方案17】:

承诺

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

可观察的

    定义:帮助您异步运行函数,并在执行时以连续序列(多次)使用它们的返回值。 默认情况下,它是惰性,因为它会随着时间的推移发出值。 拥有大量运算符,简化了编码工作。 一个运算符 retry 可用于在需要时重试,如果我们需要根据某些条件重试 observable,也可以使用 retryWhen

注意:在**RxMarbles.com**

上提供了运算符列表及其交互式图表

【讨论】:

【参考方案18】:

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

由于一个代码 sn-p 值一千字,让我们通过下面的示例更容易理解它们。

感谢@Christoph Burgdorf the awesome article


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

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

我们不希望每次用户按键时都点击服务器端点。它应该用HTTP 请求的风暴淹没他们。基本上,我们只想在用户停止输入时点击它,而不是每次击键。 对于后续请求,请勿使用相同的查询参数点击搜索端点。 处理无序响应。当我们同时处理多个请求时,我们必须考虑它们以意外顺序返回的情况。想象一下,我们首先输入computer,停止,发出一个请求,我们输入car,停止,发出一个请求。现在我们有两个正在处理的请求。不幸的是,携带 computer 结果的请求在携带 car 结果的请求之后返回。

演示将仅包含两个文件: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 服务,以针对具有给定搜索词的Wikipedia API 发出GET 请求。请注意,我们调用toPromise 是为了从Observable&lt;Response&gt;Promise&lt;Response&gt;。最终以Promise&lt;Array&lt;string&gt;&gt; 作为我们搜索方法的返回类型结束。

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 毫秒

时发送请求

为了揭示这些超能力,我们首先需要获得一个带有用户输入的搜索词的Observable&lt;string&gt;。我们可以利用 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"/>

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

在幕后,term 自动将Observable&lt;string&gt; 公开为我们可以订阅的属性valueChanges。现在我们有了Observable&lt;string&gt;,克服用户输入就像在Observable 上调用debounceTime(400) 一样简单。这将返回一个新的Observable&lt;string&gt;,它只会在 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));
  

针对我们的应用程序已经显示结果的搜索词发送另一个请求会浪费资源。为了达到预期的行为,我们所要做的就是在调用debounceTime(400) 之后立即调用distinctUntilChanged 运算符

查看Plunker上的Observable实现示例

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

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


了解更多

https://angular-2-training-book.rangle.io/handout/observables/ https://angular.io/tutorial/toh-pt6#observables

【讨论】:

我并不完全赞同将 Http 服务转变为基于 Observable 的决定。我听到的每一个解释都依赖于同一个例子:按词搜索。但那是关于处理浏览器事件的。我想听听在处理异步 http 请求时应用它有什么好处。 @AlexPollan,实际上有一个很好的解释,可以很好地解释 http 服务在 Ben Lesh 的播客上返回 observable 的好处:devchat.tv/js-jabber/…。最终,主要的好处是你可以取消一个 observable,上面链接中描述的一个用例——虽然有点做作——是如果你调用多个 api 并且只关心第一个响应,不管哪个您调用的 api 中的 api 先返回给您,然后您可以取消对其他人的请求。 @nikolasleblanc,我很确定你可以使用 $q.race() 吗? 假设您键入 foo,停止,键入另一个 o,然后立即退格并在 foo 处休息。这应该只是一个带有 foo 这个词的请求,而不是两个,即使我们在搜索框中有 foo 之后技术上停止了两次。这就是 distinctUntilChanged 所做的。您可以从learnrxjs.io/operators/filtering/distinctuntilchanged.html查看更多示例 @AlexPollan,优点是基于 Observable 的 HTTP 服务可以很容易地取消中间的 HTTP 请求。 trungk18 的答案中的竞争条件可以通过在发出后续请求之前简单地取消订阅 HTTP 可观察对象来解决。 RXJS switchMap 可用于由另一个可观察对象(例如 valueChanges)触发的 HTTP 请求。对于独立的 HTTP observables,您可以手动取消订阅和重新订阅。【参考方案19】:

承诺

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

注意:有 Promise 库支持取消,但 ES6 Promise 目前还不支持。

可观察

Observable 类似于 Stream(在许多语言中),允许传递零个或多个事件,其中每个事件都会调用回调。

通常ObservablePromise 更受欢迎,因为它提供了Promise 的功能等等。使用Observable,您是否要处理 0、1 或多个事件都没有关系。您可以在每种情况下使用相同的 API。

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

虽然Promise 会立即启动,但Observable 只有在您订阅后才会启动。这就是为什么 Observable 被称为惰性的原因。

Observable 提供 运算符,例如 mapforEachreduce,...类似于数组

还有像retry(),或replay(),...等强大的运算符,它们通常非常方便。 A list of operators shipped with rxjs

延迟执行允许在通过订阅执行 observable 之前建立一系列运算符,以进行更具声明性的编程。

【讨论】:

那么在单个回调的情况下是否有充分的理由使用 Promise 而不是 Observable 或者 Observables 也应该在那里使用,因为它们也可以这样工作?基本上,“可观察所有事物”是一种好习惯,还是 Promise 仍然有它的位置? 如果你想使用响应式风格,只需在任何地方使用 observables。如果您只有 observables,您可以轻松编写。如果你混合它们,它就不再那么干净了。如果您不关心响应式样式,则可以将 promise 用于单个事件,而您不关心事件流的可取消和可观察。 @GünterZöchbauer 嘿——我没有反对 Observables 或函数式编程的论据。我只是说我相信在 NG2 中主要通过 http 运行 Observables 的人没有任何真正的理由使用 Observables 而不是 Promises 进行调用。使用 Promise 并没有失去任何实际意义。 debounce 和 retry 运算符无关紧要 - 您可以使用 ng-debounce 进行 debounce,如果预计调用会失败,通常是代码存在问题。我需要处理重试调用的唯一一次是在为 HVT 查询不稳定的第三方 API 时。 但请不要忘记Promiseasync/await 使您的代码再次变得平坦!在大多数情况下,以及在不涉及火箭科学的项目中,没有必要用不必要的复杂方法链编写那些可怕的嵌套函数。您现在可以将async/awaitTypeScript 等转译器一起使用,并编写实际的人类可读的平面代码,而无需任何rxjs 样板。有时在某些特定情况下,您可能仍需要rxjs,因为它确实提供了很多东西。 这个答案具有误导性,一个 observable not 像一个流,它就像一个 返回流的函数【参考方案20】:

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

【讨论】:

【参考方案21】:

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

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

Frequently Observable 比 Promise 更受欢迎,因为它提供了 Promise 的亮点等等。使用 Observable,您是否需要处理 0、1 或各种事件都无关紧要。您可以对每种情况使用类似的 API。

承诺: Promise 发出单个值

例如:

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

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

承诺:

承诺不是懒惰的 不能取消承诺

可观察:

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

Angular Promises vs Observables

【讨论】:

【参考方案22】:

概述:

Promises 和 Observables 都可以帮助我们处理异步操作。当这些异步操作完成时,它们可以调用某些回调。 Promise 只能处理一个事件,Observables 用于一段时间内的事件流 承诺一旦处于待处理状态就无法取消 Data Observables 可以使用操作符进行转换

你总是可以使用 observable 来处理异步行为,因为 observable 具有 Promise 提供的所有功能(+额外)。但是,有时不需要 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 会执行一些代码,它要么解决要么拒绝。如果调用了 resolve 或 reject,则 Promise 从 pending 状态 变为 resolvedrejected 状态。当承诺状态被解决时,then() 方法被调用。当 promise 状态被拒绝时,会调用 catch() 方法。

何时使用 Observables:

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

    用户事件,例如点击或按键事件。用户随时间生成事件(数据)。 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

当创建一个 observable 时,它​​需要一个回调函数,它提供一个观察者作为参数。在这个观察者上,你可以调用onNextonCompletedonError。然后当 Observable 被订阅时,它会调用相应的回调传入订阅中。

【讨论】:

【参考方案23】:

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

以下是它们之间的区别:

可观察

    在一段时间内发出多个值 在订阅 Observable 之前不会被调用 可以使用 unsubscribe() 方法取消 提供 map、forEach、filter、reduce、retry 和 retryWhen 运算符

承诺

    一次只发出一个值

    调用不带 .then 和 .catch 的服务

    无法取消

    不提供任何运算符

【讨论】:

promise 只发出单个值,而 observable 发出多个值的确切含义是什么 一个承诺根本不会发出一个值——一个承诺随着时间的推移而产生的一个值。一个承诺将这个价值多播给多个订阅者——一旦你持有这个承诺,你就已经拥有了一个价值。一个可观察对象就像一个函数,订阅它会调用动作。 @BenjaminGruenbaum 我仍然没有得到多个订阅者的意思,请您提供链接或示例。谢谢 observable1.subscribe(subscriber1), observable1.subscribe(subscriber2) - 这会多次调用 函数 edit您的帖子并显示实际文本而不是屏幕截图。其他人无法从您的图像中复制和粘贴,也无法帮助您修复许多语法错误。 See here 了解详情。谢谢。【参考方案24】:

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

Angular 使用来自 RxJS 的 Observables 代替 Promise 来处理 HTTP

Below are some important differences in promises &amp; Observables.

【讨论】:

edit您的帖子并将实际内容显示为文本而不是屏幕截图。其他人无法从您的图像中复制和粘贴。 See here 了解详情。谢谢。【参考方案25】:

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

【讨论】:

edit您的帖子并将实际内容显示为文本而不是屏幕截图。其他人无法从您的图像中复制和粘贴。 See here 了解详情。谢谢。【参考方案26】:

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

【讨论】:

【参考方案27】:

我相信所有其他答案应该可以消除您的疑虑。 尽管如此,我只想补充一点,observables 是基于函数式编程的,我发现它附带的函数非常有用,例如 map、flatmap、reduce、zip。 Web 实现的一致性,尤其是当它依赖于 API 请求时,这是一个残酷的改进。

我强烈推荐this documentation,因为它是reactiveX 的官方文档,我发现它是最清楚的。

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

虽然它是为 RxJava 设计的,但概念是一样的,而且解释得很好。在 reactiveX 文档中,您有每个函数的等价物。你必须寻找 RxJS。

【讨论】:

【参考方案28】:

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

承诺

仅发出单个值 不可取消 不可分享 始终异步

可观察

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

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

【讨论】:

【参考方案29】:

我刚刚处理了一个问题,其中 Promise 是最好的解决方案,如果有用的话,我将在这里分享给任何偶然发现这个问题的人(这正是我之前寻找的答案):

在一个 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 方法是理想的。

【讨论】:

这对于(高阶)可观察对象当然也是可能的。例如,您可以使用 scan() 来构建顺序可观察数据流。但是,您的方法可能更明确且更易于理解。 你可以用 "switchMap" 替换 "then" 并用 observables 做同样的事情。 据我了解,switchMap 的问题在于它将并行启动所有请求并等待它们全部返回,然后将值返回给调用函数,而在我的情况下,我有我不能多次并行调用的单个服务器(因为当新请求进来时服务器会丢弃未完成的请求),所以我必须确保在开始新调用之前完成对数据库服务的每次调用,并且 Promise /then 似乎是解决这个问题的最好方法,也许是唯一的方法。 你为什么不使用链式mergeMap?据我了解您的代码,这个非常简单,并且与您的示例一样好。 @StephenR.Smith @Ore 您能否添加一个代码示例来解决与另一个答案相同的问题?将是一个很好的参考,将来可能是一个很好的重构机会。要求是任何代码不能并行调用后端服务,必须调用,等待返回值再调用。【参考方案30】:

承诺:

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

可观察:

随着时间的推移发出多个值; 懒惰; 可取消; 支持 map、filter、reduce 和类似的运算符

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

【讨论】:

以上是关于Promises 和 Observables 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Ember 的 Promises 与一般的 Promises 有啥关系,特别是 jQuery 的 Promises?

Promises => Async/Await....这有啥好处吗?

q.all 用于 angular2 observables

RX Observables - 如果我不能改变价值,那么“随着时间的推移”有啥意义?

RxJS Observables 的 Promise.all 行为?

Angular 2 “实时”更新对象。