保留中のすべてのHTTPリクエストをキャンセル/中止する方法angular 4+。
HTTPリクエストをキャンセルするunsubscribe
メソッドがありますが、保留中のリクエストをすべて一度にキャンセルする方法があります。
特にルート変更中。
私がやったことが一つあります
ngOnDestroy() {
this.subscription.unsubscribe();
}
しかし、これをグローバルに達成する方法
何か案は?
RxJSから takeUntil()
演算子をチェックアウトして、サブスクリプションをグローバルに削除します。
-RxJS 6+(pipe
構文を使用)
import { takeUntil } from 'rxjs/operators';
export class YourComponent {
protected ngUnsubscribe: Subject<void> = new Subject<void>();
[...]
public httpGet(): void {
this.http.get()
.pipe( takeUntil(this.ngUnsubscribe) )
.subscribe( (data) => { ... });
}
public ngOnDestroy(): void {
// This aborts all HTTP requests.
this.ngUnsubscribe.next();
// This completes the subject properlly.
this.ngUnsubscribe.complete();
}
}
-RxJS <6
import 'rxjs/add/operator/takeUntil'
export class YourComponent {
protected ngUnsubscribe: Subject<void> = new Subject<void>();
[...]
public httpGet(): void {
this.http.get()
.takeUntil(this.ngUnsubscribe)
.subscribe( (data) => { ... })
}
public ngOnDestroy(): void {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
基本的に、next()
を使用して、一連のストリームを完了するたびに、サブスクライブ解除Subject
でイベントを発行できます。また、メモリリークを回避するために、コンポーネントが破棄されるときにアクティブなObservableのサブスクライブを解除することをお勧めします。
読む価値があります :
インターセプターを作成して、すべてのリクエストにtakeUntil
演算子を適用できます。次に、ルートの変更時に、保留中のすべてのリクエストをキャンセルする値を送信します。
@Injectable()
export class HttpCancelInterceptor implements HttpInterceptor {
constructor(private httpCancelService: HttpCancelService) { }
intercept<T>(req: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {
return next.handle(req).takeUntil(this.httpCancelService.onCancelPendingRequests())
}
}
ヘルパーサービス。
@Injectable()
export class HttpCancelService {
private cancelPendingRequests$ = new Subject<void>()
constructor() { }
/** Cancels all pending Http requests. */
public cancelPendingRequests() {
this.cancelPendingRequests$.next()
}
public onCancelPendingRequests() {
return this.cancelPendingRequests$.asObservable()
}
}
ルートのフックは、アプリ内のどこか(アプリコンポーネントなど)で変更します。
this.router.events.subscribe(event => {
if (event instanceof ActivationEnd) {
this.httpCancelService.cancelPendingRequests()
}
})
すべてのサブスクリプションを手動でサブスクライブ解除したくない場合は、これを行うことができます。
export function AutoUnsubscribe(constructor) {
const original = constructor.prototype.ngOnDestroy;
constructor.prototype.ngOnDestroy = function() {
for (const prop in this) {
if (prop) {
const property = this[prop];
if (property && (typeof property.unsubscribe === 'function')) {
property.unsubscribe();
}
}
}
if (original && typeof original === 'function') {
original.apply(this, arguments)
};
};
}
次に、コンポーネントでデコレータとして使用できます
@AutoUnsubscribe
export class YourComponent {
}
ただし、サブスクリプションをコンポーネントプロパティとして保存する必要があります。コンポーネントから移動すると、AutoUnsubscribe機能が発生します。
要求された機能の必要性は確信していませんが、フレームワークのhttpサービスをラップして委任することで、いつでもどこでも未処理の要求をすべてキャンセルし、これを実現できます。
ただし、このサービスを実装しようとすると、問題がすぐに明らかになります。一方で、ストックAngular httpクライアントを活用するサードパーティコードを含む既存のコードの変更を避けたいと思います。一方、実装の継承は避けたいと思います。
両方の世界を最大限に活用するために、ラッパーで実装 Angular Http
サービスを利用できます。既存のコードは、変更せずに機能し続けます(コードがuse http instanceof Http
のような愚かなことをしないと述べた場合)。
import {Http, Request, RequestOptions, RequestOptionsArgs, Response} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
export default interface CancellationAwareHttpClient extends Http { }
export default class CancellationAwareHttpClient {
constructor(private wrapped: Http) {
const delegatedMethods: Array<keyof Http> = [
'get', 'post', 'put', 'delete',
'patch', 'head', 'options'
];
for (const key of delegatedMethods) {
this[key] = wrapped[key].bind(wrapped);
}
}
cancelOutstandingRequests() {
this.subscriptions.forEach(subscription => {
subscription.unsubscribe();
});
this.subscriptions = [];
}
request(url: string | Request, options?: RequestOptionsArgs) {
const subscription = this.wrapped.request(url, options);
this.subscriptions.Push(subscription);
return subscription;
}
subscriptions: Subscription[] = [];
}
interface
のclass
およびCancellationAwareHttpClient
宣言はマージされることに注意してください。このようにして、クラスimplementsHttp
は、interface
宣言のextends
句によります。
今、私たちはサービスを提供します
import {NgModule} from '@angular/core';
import {ConnectionBackend, RequestOptions} from '@angular/http';
import CancellationAwareHttpClient from 'app/services/cancellation-aware-http-client';
let cancellationAwareClient: CancellationAwareHttpClient;
const httpProvider = {
provide: Http,
deps: [ConnectionBackend, RequestOptions],
useFactory: function (backend: ConnectionBackend, defaultOptions: RequestOptions) {
if (!cancellationAwareClient) {
const wrapped = new Http(backend, defaultOptions);
cancellationAwareClient = new CancellationAwareHttpClient(wrappedHttp);
}
return cancellationAwareClient;
}
};
@NgModule({
providers: [
// provide our service as `Http`, replacing the stock provider
httpProvider,
// provide the same instance of our service as `CancellationAwareHttpClient`
// for those wanting access to `cancelOutstandingRequests`
{...httpProvider, provide: CancellationAwareHttpClient}
]
}) export class SomeModule {}
既存のフレームワークが提供するサービスをオーバーライドする方法に注意してください。ファクトリーを使用してインスタンスを作成し、インジェクターのサイクルを回避するために、DIのデコレーターをラッパー自体に追加しません。
ngOnDestroy
コールバックは通常、インスタンスが破棄されたときに発生する必要があるカスタムクリーンアップに使用されます。
どこでリクエストをキャンセルしますか?
ブラウザの近くでリクエストをキャンセルしたい場合は、創造的なアイデアがあります here
これを試して :
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Rx';
export class Component implements OnInit, OnDestroy {
private subscription: Subscription;
ngOnInit() {
this.subscription = this.route.params.subscribe();
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
//This is the example of cancelling the get request once you leave the TestComponent.
import { Component, OnInit} from '@angular/core';
@Component({
selector: 'app-test',
templateUrl: './test.component.html'
})
export class TestComponent implements OnInit {
request: any;
someList: any;
constructor( private _someService: SomeService) {
}
ngOnInit() {
this.getList();
}
ngOnDestroy(){
this.request.unsubscribe(); // To cancel the get request.
}
getList() {
this.request= this._someService.getAll()
.subscribe((response: any) => {
this.someList= response;
}, (error) => {
console.log("Error fetching List", error);
})
}
}
保留中の要求のリストを保持するカスタムHttpサービス(HttpClientを使用)を作成できます。 Http/HttpClientの代わりにこのカスタムサービスをhttpで起動すると、サブスクリプションがリストにプッシュされ、応答が返されるとそのサブスクリプションがポップされます。これを使用すると、すべての不完全なサブスクリプションがリストに表示されます。
同じカスタムサービスで、コンストラクターにルーターを挿入し、それをサブスクライブして、ルート変更イベントを取得します。このオブザーバブルが発行されるときはいつでも、リストにあるすべてのサブスクリプションのサブスクリプションを解除し、そこからすべての要素をポップするだけです。
コードスニペットが必要な場合は、コメントに記載してください。