Angular2で以前のhttp呼び出しをキャンセルするためにswitchMapを使用しようとしています。コードは基本的に
var run = ():Observable<any> => {
var url = 'http://...'
return this._http.get(url)
.map(result => {
return var xmlData:string = result.text()
});
}
function pollTasks() {
return Observable.of(1)
.switchMap(() => run())
.map(res => res)
}
// caller can do subscription and store it as a handle:
let tasksSubscription =
pollTasks()
.subscribe(data => {
console.log('aa'+data)
});
そして、私はソース全体を続けて数回呼び出し、いくつかの応答を受け取ります(つまり:aa + data)
SwitchMapは以前の呼び出しをキャンセルするべきだという印象を受けました。
リクエストは、同じ基本的なストリームから発信される必要があります。以下は、必要な処理を実行するhttpサービスインスタンスを作成するファクトリ関数です。
function httpService(url) {
// httpRequest$ stream that allows us to Push new requests
const httpRequest$ = new Rx.Subject();
// httpResponse$ stream that allows clients of the httpService
// to handle our responses (fetch here can be replaced with whatever
// http library you're using).
const httpResponse$ = httpRequest$
.switchMap(() => fetch(url));
// Expose a single method get() that pushes a new
// request onto the httpRequest stream. Expose the
// httpResponse$ stream to handle responses.
return {
get: () => httpRequest$.next(),
httpResponse$
};
}
そして今クライアントコードはこのようにこのサービスを使用することができます:
const http = httpService('http://my.api.com/resource');
// Subscribe to any responses
http.httpResponse$.subscribe(resp => console.log(resp));
// Call http.get() a bunch of times: should only get one log!!
http.get();
http.get();
http.get();
constructor(private _http:Http, private appStore:AppStore) {
this.httpRequest$ = new Subject();
this.httpRequest$
.map(v=> {
return v;
})
.switchMap((v:any):any => {
console.log(v);
if (v.id==-1||v.id=='-1')
return 'bye, cancel all pending network calls';
return this._http.get('example.com)
.map(result => {
var xmlData:string = result.text()
});
}).share()
.subscribe(e => {
})
...
データをプッシュするには:
this.httpRequest$.next({id: busId});
これはうまく機能し、すべてのネットワーク呼び出しをパイプで通したり、以前の呼び出しをキャンセルしたりできる単一のサービスを利用できるようになりました...
下の画像を参照してください。新しい通話が着信すると、以前の通話はキャンセルされます。すべてが期待どおりに機能するように、4秒の遅延のある遅いネットワークを設定したことに注意してください...
switchMap
演算子を使用する場合、現在のデータフローでのみリクエストをキャンセルできると思います。同じ監視可能なチェーンで発生するイベントを意味します...
pollTasks
メソッドを数回呼び出すと、以前のリクエストは同じデータフローにないため、キャンセルできません...メソッドを呼び出すたびに監視可能なチェーンを作成します。
リクエストの実行をトリガーする方法がわかりません。
500msごとにリクエストを実行したい場合は、これを試すことができます:
pollTasks() {
return Observable.interval(500)
.switchMap(() => run())
.map(res => res.json());
}
この場合、500ミリ秒後に進行中のリクエストがあると、新しいリクエストを実行するためにキャンセルされます
このアプローチでは、pollTasks
メソッドを1回呼び出すだけで済みます。
ユーザーイベントに基づいて非同期処理チェーンをトリガーすることもできます。たとえば、入力に文字が入力されると、次のようになります。
var control = new Control();
// The control is attached to an input using the ngFormControl directive
control.valueChanges.switchMap(() => run())
.map(res => res.json())
.subscribe(...);
DOMイベントの処理チェーンをより簡単にリンク/開始するための提案があります(fromEvent
)
このリンクを参照してください:
Subjectを使用できますが、使用する場合は、サブスクリプションを管理して公開する必要があります。間隔内でリクエストをキャンセルするObservableを返すメソッドが必要な場合は、次のようにします。
observer: Observer<CustomObject>;
debug = 0;
myFunction(someValue) {
this.observable = new Observable<CustomObject>(observer => {
if (!this.observer) {
this.observer = observer;
}
// we simulate http response time
setTimeout(() => {
this.observer.next(someValue);
this.debug++;
}, 1000);
})
.debounceTime(3000) // We cancel request withing 3s interval and take only the last one
.switchMap(fn)
.do(() => {
console.log("debug", this.debug);
});
}
ずっと同じオブザーバーを使用して、必要に応じてリクエストをキャンセルします(debounceTime、distinctUntilChanged、...)。