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

Ric*_*ico 16 subscribe angular

问题
我订阅了两次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');
  }
);
Run Code Online (Sandbox Code Playgroud)

安慰

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
Run Code Online (Sandbox Code Playgroud)

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

Jet*_*eto 25

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

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

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

import { share } from 'rxjs/operators';
Run Code Online (Sandbox Code Playgroud)

share操作者进行可观察到的hot,即,用户之间共享.但是还有更多内容,我建议这篇文章要深入探讨(你当然也可以谷歌hot vs cold observables了解更多信息).


JeB*_*JeB 5

您的观察结果很冷:

如果每当观察者订阅可观察对象,便创建其通知的产生者,则该可观察对象就是冷的。例如,可观察到的计时器很冷;每次进行订阅时,都会创建一个新计时器。

您需要“ multicast可观察的”,或者换句话说,使其变得炙手可热:

An observable is hot if the producer of its notifications is not created each time an observer subscribes to the observable. For example, an observable created using fromEvent is hot; the element that produces the events exists in the DOM?—?it’s not created when the observer is subscribed.

For this you can use share operator, but it still cannot guarantee you a single http call. Share will multicast your observable, making it shared between the subscribers, but once the http call completes it will make a new http call for new subscribers.

If you want a caching behavior (performing the call once and then providing the value to each subscriber whenever it subscribes) you should use publishReplay().refCount().

Further reading:

Publish and share operators