promise 和 Observable 的区别

882 篇文章 32 订阅
129 篇文章 6 订阅

StackOverflow 上的讨论:What is the difference between Promises and Observables?

得赞最高的一个回答:1777 赞

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

注意:有 Promise 库支持 cancellation 操作,但 ES6 Promise 到目前为止还不支持。

Observable

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

通常 Observable 比 Promise 更受欢迎,因为它提供了 Promise 的特性等等。使用 Observable,您是否要处理 0、1 或多个事件并不重要。您可以在每种情况下使用相同的 API。

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

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

Observable 提供了 map、forEach、reduce 等运算符,用法类似于数组。

还有一些强大的操作符,如 retry() 或 replay() 等,它们通常非常方便。

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

排名第二的回答:374 赞

举例说明。

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

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

我们不想在用户每次按下一个键时都访问服务器端点,如果这样做的话,服务器会被大量的 HTTP 请求淹没。 基本上,我们只想在用户停止输入后触发 HTTP 请求,而不是每次击键时触发。

对于后续请求,不要使用相同的查询参数访问搜索端点。

处理无序响应。 当我们同时有多个请求进行中时,我们必须考虑它们以意外顺序返回的情况。 想象一下,我们首先键入 computer,停止,发出请求,然后键入 car,停止,发出请求。 现在我们有两个正在进行的请求。 不幸的是,携带结果给computer 的请求在携带结果给 car 的请求之后返回。

首先看如何用 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 到 Promise。 最终以 Promise<Array> 作为我们搜索方法的返回类型。

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 循环遍历它并为我们构建一个列表。

Where Observables really shine

让我们更改我们的代码,不要在每次击键时敲击端点,而是仅在用户停止输入 400 毫秒时发送请求

为了揭示这样的超能力,我们首先需要获得一个 Observable ,它携带用户输入的搜索词。 我们可以利用 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 作为我们可以订阅的属性 valueChanges。 现在我们有了一个 Observable,获得用户输入就像在我们的 Observable 上调用 debounceTime(400) 一样简单。 这将返回一个新的 Observable,它只会在 400 毫秒内没有新值出现时才发出新值。

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

对我们的应用程序已经显示结果的搜索词发出另一个请求将是一种资源浪费。 为了实现所需的行为,我们所要做的就是在我们调用 debounceTime(400) 之后立即调用 distinctUntilChanged 运算符。

Observable 和 promise 的比较:


Pull:在拉模型下,消费者决定何时消耗或请求数据。当您创建返回值的函数时,该函数是一个生产者。然而,在调用该函数(或请求数据)之前,该函数不会产生任何东西。

调用该函数的代码是消费者。这种调用是按需发生的(或在需要时发生)。消费者决定通信策略。

Push:生产者主导推模型。任何消耗数据的人都不知道数据何时到达。他们知道数据到达时该做什么,但不决定时间。

Promises 是推模型的典型例子。Promise 可以在任务完成时产生数据或错误。传递给 promise 的回调函数不知道 promise 何时完成。但是,它可以处理成功或错误状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪子熙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值