为什么我不能在rxjs .let()操作中使用“this”关键字?

时间:2017-07-18 15:10:26

标签: javascript angular typescript rxjs abstract-class

我正在学习Typescript中的抽象类。除了this之外,handleRetry关键字在此类中的每个方法中都能正常运行。即使我尝试在该方法的顶部console.log(this.amiUrl),它也会爆炸并告诉我它无法找到它。

我已经尝试删除受保护的关键字,相信我误解了它的用法。没有变化。

Angular 4.3

Typescript 2.4.1

import { HttpHeaders, HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { ToastsManager } from 'ng2-toastr/ng2-toastr';

import { Store } from '@ngrx/store';
import * as uiActions from '../../core/store/actions/ui.actions';
import * as fromRoot from '../../core/store/reducers';

import { environment } from '../../../environments/environment';

@Injectable()
export abstract class RestService {
  protected amiUrl = environment.api;
  protected maxRetryAttempts = 3;

  constructor (
    private http: HttpClient,
    private store: Store<fromRoot.State>,
    private toastr: ToastsManager ) { }

  private get headers(): HttpHeaders {
    const headers: HttpHeaders = new HttpHeaders();
    headers.set('Authorization', 'Bearer ' + environment.accessToken);
    return headers;
  }

  protected get(url: string) {
    return this.http.get(this.amiUrl + url, { headers: this.headers })
      .let(this.handleRetry);
  }

  protected post(url: string, payload: any) {
    return this.http.post(this.amiUrl + url, payload, { headers: this.headers })
      .let(this.handleRetry);
  }

  protected delete(url: string) {
    return this.http.delete(this.amiUrl + url, { headers: this.headers })
      .let(this.handleRetry);
  } 

  protected handleRetry<T>(source: Observable<T>): Observable<T> { 
    return source.retryWhen(e => 
      e.scan((errorCount, error) => {
        if (errorCount >= this.maxRetryAttempts) {
          this.store.dispatch(new uiActions.ClearRetryNotificationAction);
          throw error;
        } else {
          this.store.dispatch(new uiActions.CreateRetryNotificationAction({ attempt: errorCount + 1, maxAttempts: this.maxRetryAttempts }))
          return errorCount + 1;
        }
      }, 0)
      .delay(2000))
  }

  protected handleError(err: HttpErrorResponse, customMessage?: string) {
    this.store.dispatch(new uiActions.CreateErrorNotificationAction(customMessage));

    console.log(err.error);
    console.log(err.status);
    console.log(err.name);
    console.log(err.message);

    if (!environment.production) {
      this.toastr.error(customMessage);
    }

    return Observable.throw(err.message);
  }
}

1 个答案:

答案 0 :(得分:1)

那是因为你传递了this.handleRetry作为回调 调用回调时,范围会更改,this不再引用RestService的实例。

要解决此问题,您有四种选择:

(1)使用bind method

...
.let(this.handleRetry.bind(this))

(2)使用arrow function

...
.let(source  => this.handleRetry(source))

(3)将方法绑定在ctor中:

constructor (
    private http: HttpClient,
    private store: Store<fromRoot.State>,
    private toastr: ToastsManager ) {

    this.handleRetry = this.handleRetry.bind(this);
}

然后当你传递this.handleRetry时,它已经绑定到实例,即使在被调用时也会保持这样。

(4)使用箭头功能代替方法:

handleRetry = <T>(source: Observable<T>): Observable<T> => {
    ...
}

这将在实例中创建一个类型为function的属性,因为它是一个箭头函数,它被绑定到它。
它不是一种方法,它不会成为原型的一部分,因此如果扩展该类,则不会继承。