在Angular中Promise和Observable之间有什么区别?

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


当前回答

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

以下是它们之间的区别:

可观察的

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

许诺

一次仅发射一个值调用不带.then和.catch的服务无法取消不提供任何操作员

其他回答

承诺与可观察到的相似性

两者都用于处理异步代码。请查看承诺示例。promise构造函数传递一个解析引用函数,当它在完成某个异步任务时被某个值调用时,该函数将被调用。const promise=new promise(解析=>{setTimeout(()=>{决心(“来自承诺的问候!”);}, 2000);});promise.then(值=>console.log(值));现在是一个可观的例子。在这里,我们还将一个函数传递给observable——一个处理异步任务的观察者。与promise中的resolve不同,它具有以下方法并订阅以代替then。所以两者都处理异步任务。现在让我们看看区别。const observable=新的observable(观察者=>{setTimeout(()=>{observer。next(“来自Observable的您好!”);}, 2000);});observable.subscribe(value=>console.log(value));


承诺与显著差异

许诺

它解析或拒绝单个值,并且可以一次处理单个值的异步任务。一个promise一旦解析了它完成的异步值,就不能再使用了。它只是一次性使用,在这里它是不够的。不可取消操作员不支持rxjs。

可观察的

能够发出多个异步值。用于处理事件或值流。假设您有一个包含大量任务或值的数组,并且您希望每次将值插入其中时都能自动处理。每当您将一个值推送到这个数组中时,它的所有订阅者都会自动收到最新的值。Observable可用于观察输入更改、重复间隔、向所有子组件广播值、web套接字推送通知等。可以随时使用退订方法取消。承诺的最后一个好部分是支持rxjs运算符。在订阅之前,您有许多管道操作符(主要是map、filter、switchMap、combineLatest等)来转换可观察数据。

简短回答:

可观察性更好。它具有所有Promise功能和额外功能。


长答案:

承诺:

一次性使用“返回数据一次”不取消一位听众无插座支持

观察结果:

数据更改时多次返回数据支持取消支撑插座支持许多侦听器,并在数据更改时通知它们支持映射、过滤和减少

在第一次阅读教程和文档时,我遇到了一个不明显的问题,那就是多播的想法。

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

一个承诺迫使你一次处理一件事,解开它的数据,处理异常,对async/await等很酷的事情有语言支持,否则就很简单了。

Observable有很多钟和哨子,但你需要了解你正在使用的力量,否则它可能被滥用。

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

你往外面看,看到雨点,所以你改变了主意。这是一个同步操作。你停止了你正在做的事情,去外面看看,得到了结果,然后回到你正在做什么。你请你旁边的哥哥检查一下今天的天气状况。当他在检查天气时,你仍然在做你正在做的事情。这是一个异步操作。你把一项任务交给了你的兄弟,等待承诺得到解决。在这种情况下,您将得到一个响应,在得到响应后,您将不再得到任何更新。这一次,你打开收音机,收听全天候播报天气状况的天气频道。在这种情况下,响应是持续的,而不是得到一个响应。此响应类似于订阅可观察的。可观测的是“天气”,订阅的是“让你不断更新的无线电信号”。只要你的收音机开着,你就会得到所有可用的更新。在你关掉收音机之前,你不会错过任何信息。当你关闭收音机时,意味着“你已取消订阅”。

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

由于一段代码相当于一千个单词,所以让我们通过下面的示例来更容易地理解它们。

感谢@Christoph Burgdorf的精彩文章


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

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

我们不希望每次用户按下键时都会触及服务器端点。它应该会向他们发出大量HTTP请求。基本上,我们只想在用户停止打字后点击它,而不是每次按键。对于后续请求,不要使用相同的查询参数到达搜索端点。处理无序响应。当我们同时处理多个请求时,我们必须考虑这些请求以意外顺序返回的情况。想象一下,我们首先键入计算机,停止,一个请求发出,我们键入汽车,停止,请求发出。现在我们有两个请求正在执行中。不幸的是,携带计算机结果的请求在携带汽车结果的请求之后返回。

演示将仅由两个文件组成:app.ts和wikipedia-service.ts。然而,在现实世界场景中,我们很可能将事情进一步拆分。


下面是一个基于Promise的实现,它不处理任何描述的边缘情况。

维基百科服务.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是为了从一个可观察的<Response>转换为Promise<Response>。最终以Promise<Array<string>作为搜索方法的返回类型。

应用程序

// 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上基于Promise的实现示例


观察者真正闪耀的地方

让我们将代码更改为不在每次击键时敲击端点,而是仅在用户停止键入400ms时发送请求

要揭示这些超级功能,我们首先需要获得一个Observable<string>,它包含用户键入的搜索项。我们可以利用Angular的formControl指令,而不是手动绑定到keyup事件。要使用此指令,我们首先需要将ReactiveFormsModule导入到应用程序模块中。

应用程序

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实例,并将其作为组件名称项下的字段公开。

在幕后,术语会自动将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 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 over Promise没有太大的区别。在实践中,没有一个优点是真正相关的。我希望将来能看到一些高级用例:)


了解更多信息https://angular-2-training-book.rangle.io/handout/observables/https://angular.io/tutorial/toh-pt6#observables