誰かがAngularのPromise
とObservable
の違いを説明できますか?
それぞれの例は、両方のケースを理解するのに役立ちます。
約束する
Promise
は 単一のイベントを処理します 非同期操作が完了または失敗したとき。
注:取り消しをサポートするPromise
ライブラリーがありますが、ES6 Promise
はこれまでにありません。
観測可能
Observable
はStream
のようなもので(多くの言語で)、各イベントに対してコールバックが呼び出されるところで0個以上のイベントを渡すことができます。
多くの場合、Observable
はPromise
以上の機能を提供するため、Promise
よりもObservable
が優先されます。 Observable
では、0、1、または複数のイベントを処理するかどうかは関係ありません。どちらの場合も同じAPIを利用できます。
Promise
はSubscription
よりも キャンセル可能 になるという利点もあります。サーバへのHTTPリクエストや他の高価な非同期操作の結果がもはや必要ではない場合、Observable
のPromise
はサブスクリプションをキャンセルすることを可能にします。通知またはそれが提供する結果がもう必要です。
Observableは 演算子 のようにmap
、forEach
、reduce
、...のように配列を提供します
retry()
やreplay()
などの強力な演算子もあります。これらは非常に便利です。
Promises
とObservables
はどちらも、アプリケーションのAsynchronousの性質を扱うのに役立つ抽象化を提供します。それらの違いは、@Günterと@Reluによって明確に指摘されています。
コードスニペットは1000語に相当するので、以下の例を見て理解しやすくしてください。
素晴らしい{ article をありがとう@Christoph Burgdorf
Angularは、HTTPを処理するための約束の代わりにRx.js Observablesを使用します。
入力した結果を即座に表示するsearch関数を作成しているとします。おなじみのように聞こえますが、そのタスクにはたくさんの課題があります。
HTTP
リクエストの洪水でそれらをあふれさせるべきです。基本的には、ユーザーがキーを押すたびに入力するのではなく、入力をやめた後にヒットさせたいだけです。デモは単にapp.ts
とwikipedia-service.ts
の2つのファイルで構成されます。実社会のシナリオでは、もっとも可能性が高いでしょう。
下記はPromise-basedの実装で、説明されているEdgeのケースを処理しません。
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]);
}
}
与えられた検索語でWikipedia APIに対してJsonp
リクエストを行うためにGET
サービスを注入しています。 Observable<Response>
からPromise<Response>
に到達するためにtoPromise
を呼び出すことに注意してください。最終的に私たちの検索メソッドの戻り値の型として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-basedの実装例を参照してください
Observablesが本当に輝く場所
すべてのキーストロークでエンドポイントを邪魔するのではなく、ユーザーが400 msの入力をやめたときにのみリクエストを送信するようにコードを変更しましょう
このような超大国を明らかにするためには、まずユーザーが入力する検索語を含む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"/>
私たちのコンポーネントでは、@angular/form
からFormControl
のインスタンスを作成し、それを私たちのコンポーネントの名前termの下のフィールドとして公開します。
舞台裏では、termは私たちが購読できるプロパティvalueChanges
としてObservable<string>
を自動的に公開します。 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 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
演算子を呼び出すだけで、目的の動作を達成することができます。
Plunker でのObservableの実装例を見る
アウトオブオーダーの回答については、記事 { http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in.html>を参照してください。 -angular2.html
AngularでHttpを使用している限り、通常の使用例ではObservable over Promiseを使用しても大きな違いはないということに同意します。利点のどれも実際にここに実際に関連していません。私は将来的にいくつかの高度なユースケースを見ることができると思います:)
もっと詳しく知る
Promises および Observables の両方を使用すると、JavaScriptで 非同期機能 を使用するのに役立ちます。これらは多くの場合非常に似ていますが、2つの間にはまだいくつかの違いがあります。promiseは http callのようにasynchronous
の方法で解決される値です。一方、観測量は 非同期イベント のシーケンスを扱います。それらの主な違いは以下のとおりです。
約束:
観測可能:
また、違いを視覚的に示すために、下にグラフィカルイメージを作成しました。
約束
オブザーバブル
1つの演算子retryを使用して、必要なときにいつでも再試行できます。また、いくつかの条件に基づいてobservableを再試行する必要がある場合 retryWhenを使用できます。
注:演算子のリストとそのインタラクティブな図は、 RxMarbles.com
答えに行方不明のオブザーバブルの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)
}
この答えは遅れていますが、私は以下の違いをまとめました、
観測可能:
function
で、an observer
を取り、function Observer: an object with next, error.
を返します。subscribe/unsubscribe
を許可し、次の値をオブザーバに発行します、notify
およびerrors
およびについてのオブザーバstream completion
についてオブザーバに通知するfunction to handle next value
、エラーおよびストリームの終わり(UIイベント、http応答、Webソケットを持つデータ)を提供します。multiple values
と共に動作するcancel-able/retry-able
で、map,filter,reduce
などの演算子をサポートします。Observable.create()
- return - Observer Observable.from()
- にメソッドを呼び出すことができるObservableを使用します。 ] - Observable Observable.fromEvent()
- イベントをObservableに変換する - Observable.fromPromise()
- PromiseをObservableに変換する - Observable.range()
- 指定された範囲の整数の並び約束 :
約束は将来的に終了するタスクを表します。
約束はresolved by a value
になります。
約束は例外によって拒否されます。
cancellable
ではなく、a single value
を返します。
約束は関数を公開する(then)
-thenは新しいpromise
を返します。
attachment
に対する許可はstate
に基づいて実行されます。
- handlers
areguaranteed
はorder attached
で実行されます。
それでも、オブザーバブルは関数型プログラミングに基づいていることを付け加えたかっただけで、map、flatmap、reduce、Zipのようなそれに付随する関数は非常に有用だと思います。 。 WebがAPIリクエストに依存する場合に特に達成される一貫性は、残酷な改善です。
this documentation を強くお勧めします。これはreactXの公式文書であり、そこから最も明確なものであることがわかったためです。
あなたが観測量に入りたいならば、私はこの3部のポストを提案するでしょう: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
それはRxJavaのためのものですが、概念は同じです、そしてそれは本当によく説明されています。 activeXのドキュメントでは、あなたはそれぞれの関数に同等のものを持っています。あなたはRxJSを探す必要があります。
私はPromiseが最善の解決策であるという問題に対処しました、そしてそれがここで私がそれを有用である場合にこの質問に出くわす誰かのために共有します。
Angular 2プロジェクトでは、いくつかのパラメータを受け取り、フォーム上のドロップダウンメニューに値を設定するための値リストを返すサービスがあります。フォームコンポーネントが初期化されるとき、私は異なるパラメータで同じサービスを複数回呼び出す必要がありますが、サービスを呼び出すためにすべての変数を単純にキューに入れると、最後のものだけが成功し残りのエラーが発生します。でる。データベースから取得するサービスは、一度に1つの要求しか処理できませんでした。
すべてのドロップダウンメニュー変数を正しく生成する唯一の方法は、最後の要求が完了するまで新しい要求が処理されないようにサービスを呼び出すことです。Promise/ .thenメカニズムは問題をうまく解決しました。
fetchValueList(listCode): Promise<any> {
return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
.map(response => response.json())
.toPromise();
}
initializeDropDowns() {
this.fetchValueList('First-Val-List')
.then(data => {
this.firstValList = data;
return this.fetchValueList('Second-Val-List')
}).then(data => {
this.secondValList = data;
return this.fetchValueList('Third-Val-List')
}).then(data => {
this.thirdValList = data;
}) }
コンポーネント内で関数を定義してから、ngOnInitでinitializeDropDowns()を呼び出しました。
FetchValueList関数はPromiseを返すので、最初の呼び出しで最初のlistCodeが渡され、Promiseが解決されると、戻り値はthis.firstValList変数に割り当てることができる.thenブロック内のデータ変数にあります。関数がデータを返したので、サービスが終了したことがわかり、2番目のlistCodeを使って再度呼び出しても安全です。戻り値は次の.thenブロックのdata変数にあり、this.secondValList変数に割り当てます。
すべての変数を設定するのに必要なだけ連鎖することができ、最後のコードブロックでは単にreturnステートメントを省略してブロックを終了します。
これは、コンポーネントが初期化されるときに複数回呼び出す必要がある単一のサービスがあり、サービスが再度呼び出しを行う前にフェッチを完了して値を返さなければならない、非常に特殊な使用例です。 Promise/.then方法が理想的でした。
Observableはpromiseが提供するすべての機能を備えているため(+余分)、常に非同期動作を処理するためにObservableを使用できます。ただし、Observablesが提供するこの追加機能は必要ない場合があります。次に、ライブラリをインポートして使用するために余分なオーバーヘッドが発生します。
結果を処理するsingle非同期操作がある場合は、promiseを使用します。例えば:
var promise = new Promise((resolve, reject) => {
// do something once, possibly async
// code inside the Promise constructor callback is getting executed synchronously
if (/* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
//after the promise is resolved or rejected we can call .then or .catch method on it
promise.then((val) => console.log(val)) // logs the resolve argument
.catch((val) => console.log(val)); // logs the reject argument
したがって、promiseは、解決または拒否するコードを実行します。解決または拒否のいずれかが呼び出された場合、promiseは保留状態からresolvedまたはrejected状態になります。 promise状態が解決されると、then()
メソッドが呼び出されます。約束状態が拒否されると、catch()
メソッドが呼び出されます。
(データの)時間の流れを処理する必要がある場合は、Observablesを使用します。ストリームは、利用可能になっているデータ要素のシーケンスですover time。ストリームの例は次のとおりです。
Observable自体は、次のイベントが発生した場合、-エラーが発生した場合の場合、またはObservableが完了の場合に指定されます。次に、このobservableをサブスクライブしてアクティブにし、このサブスクリプションで3つのコールバックを渡すことができます(常にすべてを渡す必要はありません)。成功の場合は1つのコールバック、エラーの場合は1つのコールバック、完了の場合は1つのコールバック。例えば:
const observable = Rx.Observable.create(observer => {
// create a single value and complete
observer.onNext(1);
observer.onCompleted();
});
source.subscribe(
x => console.log('onNext: %s', x), // success callback
e => console.log('onError: %s', e), // error callback
() => console.log('onCompleted') // completion callback
);
// first we log: onNext: 1
// then we log: onCompleted
オブザーバブルを作成する場合、オブザーバーを引数として提供するコールバック関数が必要です。このオブザーバで、onNext
、onCompleted
、onError
を呼び出すことができます。その後、Observableがサブスクライブされると、Observableはサブスクリプションに渡された対応するコールバックを呼び出します。
約束 - 単一の将来価値を提供します。怠け者ではありません。キャンセルできません。それは拒否するか解決するでしょう。
観察可能 - 複数の将来価値を提供します。怠け者キャンセル可能それは他の方法ライブマップ、フィルタ、リデュースを提供します。
ObservablesとPromiseはどちらもJavaScriptの async アクティビティを扱う手段を提供します。単一の非同期イベント(http request)の完了に基づいて reject/resolve のいずれかを約束しますが、Observablesはそれらに加入しているオブザーバーに基づいて状態の変化を継続的に出すことができます。
それらの間の1つの基本的な違いは、オブザーバブルが キャンセル 要求 - 再送信 新しい方法を提供することです。約束としてそのような機能を許可しないところ。
また、Observableが複数の値を発行するのに対し、Promiseは単一の値を発行します。そのため、HTTPリクエストを処理している間、Promiseは同じリクエストに対する単一のレスポンスを管理できますが、同じリクエストに対して複数のレスポンスがある場合は、Observableを使用する必要があります。
const promise = new Promise(resolve => {
setTimeout(() => {
resolve("Hello from a Promise!");
}, 2000);
});
promise.then(value => console.log(value));
観察可能な例です。ここでも、非同期タスクを処理するオブザーバであるobservableに関数を渡します。 promiseのresolveとは異なり、次のメソッドがあり、thenの代わりにサブスクライブします。
したがって、両方が非同期タスクを処理します。それでは、違いを見てみましょう。
const observable = new Observable(observer => {
setTimeout(() => {
observer.next('Hello from a Observable!');
}, 2000);
});
observable.subscribe(value => console.log(value));
約束
観測可能
以下は、約束とオブザーバブルの重要な違いです。
約束
観測可能
よりよく理解するために https://stackblitz.com/edit/observable-vs-promises を参照してください。
一般的に受け入れられている答えは良いのですが、Angular Componentsを扱うときはキャンセルをサポートしているのでObservableを使いたいということをほとんど強調しません。たとえあなたのコンポーネントが破壊されたとしても、約束はキャンセルすることができず、解決されます。 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();
});
}
約束が解決される前にあなたのコンポーネントが破壊されると、約束が解決されたときにattempt to use destroyed view
エラーが発生します。
あるいは、 takeUntil パターンを使用してオブザーバブルを使用すると、コンポーネントが破棄されるとすぐにサブスクリプションはキャンセルされます。
これはちょっと人為的な例ですが、破壊されたコンポーネントに対してコードを実行すると、おそらくバグが発生するでしょう。何らかの理由で実際にそうしたいのでなければ、p:
短い答え :
観測可能 is より良い 、それにすべての 約束 機能と追加機能があります。
長い答え:
約束:
観測可能:
Observableは「キャンセル可能」であるという議論を使用している多くの人々を見ていますが、Promiseを「キャンセル可能」にすることはどちらかといえば簡単です。
function cancellablePromise(body) {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res; reject = rej;
body(resolve, reject)
})
promise.resolve = resolve;
promise.reject = reject;
return promise
}
// Example 1: Reject a promise prematurely
const p1 = cancellablePromise((resolve, reject) => {
setTimeout(() => resolve('10', 100))
})
p1.then(value => alert(value)).catch(err => console.error(err))
p1.reject(new Error('denied')) // expect an error in the console
// Example: Resolve a promise prematurely
const p2 = cancellablePromise((resolve, reject) => {
setTimeout(() => resolve('blop'), 100)
})
p2.then(value => alert(value)).catch(err => console.error(err))
p2.resolve(200) // expect an alert with 200
約束:
非同期イベントハンドラ - Promiseオブジェクトは、非同期操作の最終的な完了(または失敗)とその結果の値を表します。
構文: new Promise(エグゼキュータ)。
例:
var promise_eg = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise_eg.then(function(value) {
console.log(value);
// expected output: "foo"
});
console.log(promise_eg);
Promiseについて: パイプラインが1つあるため、呼び出されたときに1回だけ値が返されます。その一方向ハンドラーは一度呼ばれるとキャンセルできないかもしれません。あなたが遊ぶことができる便利な構文、 when() そして then()
観測量:
オブザーバブルは時間の経過とともに複数の値を遅延収集したものです。これは非同期操作に対する本当に優れたアプローチです。クロスプラットフォームをサポートしている rxjs を使って行うことができます。
ストリームライナーのように動作します。マルチパイプラインにすることができます。そのため、一度定義すると、さまざまな場所で結果を取得するために登録できます。
構文: initへのimport * as Rx from "@reactivex/rxjs";
:
Rx.Observable.fromEvent(button, "click"),
Rx.Subject()
等
購読するには:RxLogger.getInstance();
例:
import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';
range(1, 200).pipe(
filter(x => x % 2 === 1),
map(x => x + x)
).subscribe(x => console.log(x));
それはマルチパイプラインをサポートしているので、あなたは購読することができます別の場所に結果をもたらす、 約束よりも多くの可能性があります。
使用法: map, filter, pipe, map, concatMap etc
のようにもっと可能性があります
私が遭遇したことがチュートリアルとドキュメントの最初の読書から明らかではなかったことはマルチキャストの考えでした。
デフォルトでは、複数のサブスクリプションがObservable内で複数の実行を引き起こすことに注意してください。単一のHTTP呼び出しへの複数のサブスクリプションObservableは、あなたが.share()
(マルチキャストを有効にする)しない限り、複数の同一のHTTP呼び出しを引き起こします。
約束は、あなたが一度に一つのことに対処し、そのデータをアンラップし、例外を処理し、async/awaitのようなクールなものを言語サポートし、それ以外の場合はほとんど必要ないことを強制します。
オブザーバブルにはたくさんの鐘と笛がありますが、あなたが働いている力を理解する必要があります。そうしないと誤用される可能性があります。