1709

What is the difference between Promise and Observable in Angular?

An example on each would be helpful in understanding both the cases. In what scenario can we use each case?

4

31 に答える 31

1891

約束

は、非同期操作が完了または失敗したときに1 つのイベントPromiseを処理します。

注:Promiseキャンセルをサポートするライブラリはありますが、ES6は今のところサポートPromiseしていません。

観察可能

AnObservableStream(多くの言語で) に似ており、イベントごとにコールバックが呼び出される 0 個以上のイベントを渡すことができます。

などの機能を提供するため、しばしばObservable好まれます。0、1、または複数のイベントを処理するかどうかは問題ではありません。いずれの場合も同じ API を利用できます。PromisePromiseObservable

Observableまた、キャンセルPromise可能であるという利点もあります。サーバーへの HTTP 要求またはその他の高価な非同期操作の結果が不要になった場合、 のはサブスクリプションをキャンセルできますが、 は通知が不要な場合でも最終的に成功または失敗のコールバックを呼び出します。またはそれが提供する結果。SubscriptionObservablePromise

Promiseはすぐに開始さObservableれますが、 はサブスクライブした場合にのみ開始されます。これが、Observable がレイジーと呼ばれる理由です。

Observable は、、、 ... のような配列に似た演算子を提供しますmapforEachreduce

retry(), または, ...などの強力な演算子もありreplay()、非常に便利です。 rxjs に同梱されているオペレーターのリスト

遅延実行により、オブザーバブルがサブスクライブによって実行される前に一連の演算子を構築し、より宣言的な種類のプログラミングを行うことができます。

于 2016-05-21T17:19:35.403 に答える
396

との両方が、アプリケーションの非同期性に対処するのに役立つ抽象化を提供しPromisesます。それらの違いは、Günterと @Reluによって明確に指摘されました。Observables

コード スニペットは 1000 語に相当するため、理解を容易にするために以下の例を見てみましょう。

素晴らしい記事をありがとう@Christoph Burgdorf


Angular は、HTTP を処理するために Promise の代わりに Rx.js Observables を使用します。

入力するとすぐに結果が表示される検索機能を構築しているとします。おなじみのように聞こえますが、そのタスクには多くの課題が伴います。

  • ユーザーがキーを押すたびにサーバー エンドポイントにアクセスしたくありません。HTTPリクエストの嵐でそれらをフラッディングする必要があります。基本的に、すべてのキーストロークではなく、ユーザーがタイピングをやめたときにのみヒットしたいと考えています。
  • 後続のリクエストで同じクエリ パラメータを使用して検索エンドポイントをヒットしないでください。
  • 順不同の応答に対処します。同時に複数のリクエストが進行中の場合、それらが予期しない順序で戻ってくるケースを考慮する必要があります。最初にcomputerと入力して停止すると、リクエストが送信され、次にcarと入力して停止すると、リクエストが送信されると想像してください。現在、進行中のリクエストが 2 つあります。残念ながら、computerの結果を運ぶリクエストは、 carの結果を運ぶリクエストの後に戻ってきます。

app.tsデモは単純にとの 2 つのファイルで構成されますwikipedia-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サービスを注入して、特定の検索語でウィキペディア APIに対してGET要求を行います。anから aに取得するために呼び出していることに注意してください。最終的に、検索メソッドの戻り値の型は a になります。toPromiseObservable<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)

WikipediaService の検索メソッドが返すPromiseの結果をアンラップし、それを単純な文字列の配列としてテンプレートに公開して、それを*ngForループしてリストを作成できるようにします。

PlunkerでのPromise ベースの実装の例を参照してください。


オブザーバブルが本当に輝く場所

コードを変更して、キーストロークごとにエンドポイントを叩くのではなく、代わりにユーザーが入力を400 ミリ秒停止したときにのみリクエストを送信するようにしましょう。

このような超能力を明らかにするには、まずObservable<string>、ユーザーが入力した検索語を保持する を取得する必要があります。 keyup イベントに手動でバインドする代わりに、Angular のformControlディレクティブを利用できます。このディレクティブを使用するには、まず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"/>

FormControlこのコンポーネントでは、 fromのインスタンスを作成し、@angular/formそれをコンポーネントの名前 term の下のフィールドとして公開します。

舞台裏では、termはサブスクライブできるObservable<string>as プロパティを自動的に公開します。valueChangesができたので、ユーザー入力を克服するのは、 を呼び出すのObservable<string>と同じくらい簡単です。これは、400 ミリ秒の間新しい値が来ていない場合にのみ新しい値を発行するnew を返します。debounceTime(400)ObservableObservable<string>

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

アプリケーションがすでに結果を表示している検索用語に対して別のリクエストを送信するのは、リソースの無駄です。目的の動作を実現するために必要なのは、呼び出したdistinctUntilChanged直後にオペレーターを呼び出すことだけですdebounceTime(400)

PlunkerでのObservable実装の例を参照してください。

順不同の応答に対処するには、記事全文 http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.htmlを確認してください。

私が Angular で HTTP を使用している限り、通常の使用例では、Observable を Promise で使用しても大きな違いはないことに同意します。実際には、ここで実際に関連する利点はありません。将来的に高度なユースケースが見られることを願っています:)


もっと詳しく知る

于 2016-10-19T15:17:47.783 に答える
106

回答に欠けている Observables の欠点が 1 つあります。Promise では、ES7 の async/await 関数を使用できます。それらを使用すると、同期関数呼び出しのように非同期コードを記述できるため、コールバックはもう必要ありません。Observables がこれを行う唯一の可能性は、それらを Promise に変換することです。しかし、それらを Promise に変換すると、再び 1 つの戻り値しか持てなくなります。

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

さらに読む: Rx Observable で「待機」するにはどうすればよいですか?

于 2017-06-28T20:45:08.100 に答える
86

約束

  1. 定義: 関数を非同期で実行し、その戻り値 (または例外) を使用するのに役立ちますが、実行時に1 回だけです。
  2. 怠け者ではない
  3. キャンセル不可 (キャンセルをサポートする Promise ライブラリがありますが、ES6 Promise は今のところサポートしていません)。考えられる決定は次の 2 つです。
    • 拒絶
    • 解決
  4. 再試行できません(Promise は、再試行機能を持つ Promise を返した元の関数にアクセスできる必要があります。これは悪い習慣です)

オブザーバブル

  1. 定義: 関数を非同期に実行し、実行時に戻り値を連続シーケンス (複数回) で使用するのに役立ちます。
  2. デフォルトでは、時間が経過すると値を発行するため、遅延しています。
  3. コーディング作業を簡素化する多くの演算子があります。
  4. 1 つのオペレーターの再試行を使用して、必要に応じていつでも再試行できます。また、いくつかの条件に基づいてオブザーバブルを再試行する必要がある場合は、retryWhenを使用できます。

: オペレータのリストとインタラクティブな図は、**RxMarbles.com **で入手できます。

于 2017-01-09T18:29:50.417 に答える
14

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
于 2019-12-30T07:32:44.163 に答える
5

Günter Zöchbauer の回答は一般的には良いものですが、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 が解決される前にコンポーネントが破棄されたattempt to use destroyed view場合、promise が解決されたときにエラーが発生します。

あるいは、オブザーバブルをtakeUntilパターンで使用すると、コンポーネントが破棄されるとすぐにサブスクリプションがキャンセルされます。

これは少し不自然な例ですが、破棄されたコンポーネントのコードを実行すると、おそらくバグが発生します。

于 2018-11-14T13:36:01.650 に答える
5

チュートリアルとドキュメンテーションを最初に読んだだけでは分からなかったのは、マルチキャストのアイデアでした。

デフォルトでは、複数のサブスクリプションが Observable で複数の実行をトリガーすることに注意してください。単一の HTTP 呼び出しに対する複数のサブスクリプション Observable は、.share()(マルチキャストを有効にしない限り) 複数の同一の HTTP 呼び出しをトリガーします。

promise では、一度に 1 つのことを処理し、そのデータをアンラップし、例外を処理し、async/await などの優れた機能を言語でサポートする必要があり、それ以外はかなり必要最小限です。

Observable にはさまざまなオプションがありますが、使用しているパワーを理解する必要があります。

于 2019-02-13T22:45:43.777 に答える
-1

このトピックにはすでに多くの回答があるため、冗長なものは追加しません。

しかし、 Observable / Angularの学習を始めたばかりで、 Promiseと比較してどちらを使用するべきか疑問に思っている人には、すべてを Observable のままにして、プロジェクト内の既存のすべての Promises を Observable に変換することをお勧めします。

単純に、Angular フレームワーク自体とそのコミュニティがすべて Observable を使用しているからです。そのため、フレームワーク サービスまたはサード パーティのモジュールを統合し、すべてをチェーン化すると有益です。


もちろん、すべてのケースで 100% 正しい意見はありませんが、少なくとも Angular フレームワークで実装された通常の商用プロジェクトでは 98% の確率で Observable が正しい方法だと思います。

単純な趣味のプロジェクトの開始時点でそれが気に入らなかったとしても、Angular でやり取りするほとんどすべてのコンポーネントと、Angular に適したサードパーティ フレームワークのほとんどが Observables を使用していることにすぐに気付くでしょう。彼らと通信するために、常に Promise を Observable に変換することになります。

これらのコンポーネントには、HttpClient、フォーム ビルダー、Angular マテリアル モジュール/ダイアログ、Ngrx ストア/エフェクト、および ngx-bootstrap が含まれますが、これらに限定されません。

実際、私が過去 2 年間に扱った Angular エコシステムからの Promise はAPP_INITIALIZER.

于 2018-07-29T10:30:08.660 に答える