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?
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?
約束
は、非同期操作が完了または失敗したときに1 つのイベントPromise
を処理します。
注:Promise
キャンセルをサポートするライブラリはありますが、ES6は今のところサポートPromise
していません。
観察可能
AnObservable
はStream
(多くの言語で) に似ており、イベントごとにコールバックが呼び出される 0 個以上のイベントを渡すことができます。
などの機能を提供するため、しばしばObservable
好まれます。0、1、または複数のイベントを処理するかどうかは問題ではありません。いずれの場合も同じ API を利用できます。Promise
Promise
Observable
Observable
また、キャンセルPromise
可能であるという利点もあります。サーバーへの HTTP 要求またはその他の高価な非同期操作の結果が不要になった場合、 のはサブスクリプションをキャンセルできますが、 は通知が不要な場合でも最終的に成功または失敗のコールバックを呼び出します。またはそれが提供する結果。Subscription
Observable
Promise
Promise
はすぐに開始さObservable
れますが、 はサブスクライブした場合にのみ開始されます。これが、Observable がレイジーと呼ばれる理由です。
Observable は、、、 ... のような配列に似た演算子を提供しますmap
forEach
reduce
retry()
, または, ...などの強力な演算子もありreplay()
、非常に便利です。
rxjs に同梱されているオペレーターのリスト
遅延実行により、オブザーバブルがサブスクライブによって実行される前に一連の演算子を構築し、より宣言的な種類のプログラミングを行うことができます。
との両方が、アプリケーションの非同期性に対処するのに役立つ抽象化を提供しPromises
ます。それらの違いは、Günterと @Reluによって明確に指摘されました。Observables
コード スニペットは 1000 語に相当するため、理解を容易にするために以下の例を見てみましょう。
素晴らしい記事をありがとう@Christoph Burgdorf
Angular は、HTTP を処理するために Promise の代わりに Rx.js Observables を使用します。
入力するとすぐに結果が表示される検索機能を構築しているとします。おなじみのように聞こえますが、そのタスクには多くの課題が伴います。
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 になります。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)
。
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)
Observable
Observable<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 で使用しても大きな違いはないことに同意します。実際には、ここで実際に関連する利点はありません。将来的に高度なユースケースが見られることを願っています:)
もっと詳しく知る
回答に欠けている 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)
}
約束
オブザーバブル
注: オペレータのリストとインタラクティブな図は、**RxMarbles.com **で入手できます。
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
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パターンで使用すると、コンポーネントが破棄されるとすぐにサブスクリプションがキャンセルされます。
これは少し不自然な例ですが、破棄されたコンポーネントのコードを実行すると、おそらくバグが発生します。
チュートリアルとドキュメンテーションを最初に読んだだけでは分からなかったのは、マルチキャストのアイデアでした。
デフォルトでは、複数のサブスクリプションが Observable で複数の実行をトリガーすることに注意してください。単一の HTTP 呼び出しに対する複数のサブスクリプション Observable は、.share()
(マルチキャストを有効にしない限り) 複数の同一の HTTP 呼び出しをトリガーします。
promise では、一度に 1 つのことを処理し、そのデータをアンラップし、例外を処理し、async/await などの優れた機能を言語でサポートする必要があり、それ以外はかなり必要最小限です。
Observable にはさまざまなオプションがありますが、使用しているパワーを理解する必要があります。
このトピックにはすでに多くの回答があるため、冗長なものは追加しません。
しかし、 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
.