web-dev-qa-db-ja.com

Angular2:switchMapが以前のhttp呼び出しをキャンセルしない

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は以前の呼び出しをキャンセルするべ​​きだという印象を受けました。

15
born2net

リクエストは、同じ基本的なストリームから発信される必要があります。以下は、必要な処理を実行する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();
21
Calvin Belden
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秒の遅延のある遅いネットワークを設定したことに注意してください...

enter image description here

7
born2net

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

このリンクを参照してください:

3

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、...)。

0
marvinroller