Angular 2可观察订阅两次执行两次调用

时间:2018-03-10 11:30:33

标签: angular subscribe

问题
我订阅了两次httpClient.get observable。但是,这意味着我的调用会被执行两次。这是为什么?

证明
对于我做的每个订阅(),我在登录页面中得到另一行。

代码(来自登录页面按钮的onSubmit())

var httpHeaders = new HttpHeaders()
  .append("Authorization", 'Basic ' + btoa(this.username + ':' + this.password));

var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders});
observable.subscribe(
  () => {
    console.log('First request completed');
  },
  (error: HttpErrorResponse) => {
    console.log('First request error');
  }
);
observable.subscribe(
  () => {
    console.log('Second request completed');
  },
  (error: HttpErrorResponse) => {
    console.log('Second request error');
  }
);

控制台

zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:54 First request error
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:62 First request error

无关背景
我有一个LogonService对象来处理我的登录功能。它包含一个布尔变量,显示我是否登录。每当我调用login函数时,它都会订阅httpClient.get的observable,将login变量设置为true或false。但是login函数也返回了observable,它被订阅了。花了我一些时间将双重请求链接到双重订阅。如果有更好的方法来跟踪登录而不是通过变量,请告诉我!我正在努力学习角度:)

4 个答案:

答案 0 :(得分:13)

尝试在HttpClient.get的结果上使用share运算符,如下所示:

var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders })
  .pipe(share());

您需要在脚本之上添加以下导入:

import { share } from 'rxjs/operators';

share运算符生成可观察的hot,即在订阅者之间共享。但是还有更多内容,我建议this article深入了解(你当然也可以谷歌hot vs cold observables来寻找更多信息)。

答案 1 :(得分:2)

您的观察结果很冷:

  

如果创建了通知的生产者,则observable很冷   只要观察者订阅了观察者。例如,a   计时器可观察是冷的;每次订阅时,都会有新的订阅   计时器已创建。

您需要multicast您的Observable,或换句话说,让它变热:

  

如果其通知的制作者不是,则观察者很热   每次观察者订阅观察者时都会创建。对于   例如,使用fromEvent创建的observable很热;元素   产生事件的东西存在于DOM中 - 它不是在创建时创建的   观察者已订阅。

为此您可以使用share运算符,但它仍然无法保证您只能进行一次http调用。共享将multicast您的可观察对象,使其在订阅者之间共享,但一旦http呼叫完成,它将为新订阅者进行新的http呼叫。

如果您需要缓存行为(执行一次调用,然后在订阅时为每个订阅者提供值),您应该使用publishReplay().refCount()

进一步阅读:

Publish and share operators

答案 2 :(得分:0)

除了以上答案外,您还可以将http服务分配给可观察的服务,然后订阅获取数据。例如:

export class App implements OnInit {

cars$: Observable<Car[]>;

constructor(private carsService: carsService) {

}

ngOnInit() {
    this.lessons$ = this.lessonsService.loadLessons().publishLast().refCount();

    this.lessons$.subscribe(
         () => console.log('lessons loaded'),
         console.error
         );
    }
}

The Angular documentation.

答案 3 :(得分:-2)

http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html

  

调用Observable的执行并注册Observer处理程序   对于它将发出的通知。