承诺和可观察性有什么区别?

angular promise rxjs angular-promise angular-observable


Promise 和Angular中的 Observable 有什么区别?

每一种情况下的例子都会对理解这两种情况有帮助。我们可以在什么情况下使用这两种情况?




Answer 1 Günter Zöchbauer


Promise

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

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

Observable

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

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

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

Observable提供类似于数组的 mapforEachreduce ,... 等运算符

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




Answer 2 trungk18


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

既然一个代码片段的价值千言万语,那么下面的例子就简单的说一下,让我们去理解一下。

感谢@Christoph Burgdorf的精彩文章


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

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

  • 我们不想每次用户按下一个键都击中服务器端点,它应该向他们发出大量 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 服务,以使用给定的搜索词针对Wikipedia API发出 GET 请求。注意,我们调用 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)

我们解开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"/>

在我们的组件中,我们从 @angular/form 创建一个 FormControl 实例,并将其作为一个字段显示为组件上名称项下的字段。

在幕后,term自动将 Observable<string> 公开为我们可以订阅的属性 valueChanges 。现在我们有了一个 Observable<string> ,克服用户输入就像在 Observable 上调用 debounceTime(400) 一样容易。这将返回一个新的 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比Promise没有太大的区别。在实际应用中,这些优势都不存在。希望我将来能看到一些高级用例:)


了解更多




Answer 3 Alireza


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

promise:

  • 一条管线
  • 通常只和Async数据一起使用
  • 不容易取消

observable:

  • 可取消
  • 是可重试和重试的性质,如重试和重试When
  • 多管道数据流
  • 类似于数组的操作,如映射、过滤等
  • 可以从其他来源如事件中创建
  • 它们是功能,以后可以订阅

另外,我在下面为大家制作了图文并茂的图片,让大家直观的感受到其中的差异。

Promises and Observables image




Answer 4 Aravind


Promises

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

Observables

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

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




Answer 5 besserwisser


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

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

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