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

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


当前回答

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

承诺在应用程序中自动执行,而可观测则是惰性的。所以我们必须订阅可观测值以返回数据。

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

其他回答

我相信所有其他的答案都会消除你的疑虑。然而,我只是想补充一点,可观测性是基于函数式编程的,我发现它附带的函数非常有用,比如map、flatmap、reduce、zip。web实现的一致性,尤其是当它依赖于API请求时,是一种残酷的改进。

我强烈推荐这个文档,因为它是reactiveX的官方文档,我发现它是最清晰的。

如果你想了解可观测性,我建议你写一篇三部分的文章:http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

虽然它是针对RxJava的,但概念是相同的,而且解释得很好。在reactiveX文档中,您拥有每个函数的等效项。您必须查找RxJS。

承诺只针对单一价值或解决方案。可观测数据是数据流。可观的东西可以取消,但承诺不能取消。

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

承诺总是异步的,但可观测可以是同步的和异步的。

如果你想详细了解它,我写了一篇关于这个答案的博客文章——JavaScript中Observables和Promise之间的4个区别

我看到很多人认为Observable是“可取消的”,但将Promise设为“可取消”并不重要

函数cancelablePromise(主体){让决心,拒绝;const promise=新的promise((res,rej)=>{分辨率=res;拒绝=rej;正文(解析,拒绝)})promise.resolve=决议;promise.reject=拒绝;退货承诺}//示例1:过早拒绝承诺const p1=可取消承诺((resolve,reject)=>{setTimeout(()=>解析(“10”,100))})p1.then(value=>alert(value)).catch(err=>console.error(err))p1.拒绝(新错误('denid'))//控制台中出现错误//示例:过早地解决承诺const p2=可取消承诺((resolve,reject)=>{setTimeout(()=>解析('blop'),100)})p2.then(value=>alert(value)).catch(err=>console.error(err))p2.resolve(200)//预期警报为200

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

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

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

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

即时搜索示例:

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