【问题标题】:Angular 2 observable subscribing twice executes call twiceAngular 2 observable 订阅两次执行调用两次
【发布时间】:2018-08-18 21:32:57
【问题描述】:

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

证明
对于我执行的每一个 subscribe(),我都会在登录页面中得到另一行。

代码(来自登录页面按钮的 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。我花了一些时间将双重请求链接到双重订阅。如果有比通过变量更好的方法来跟踪登录,请告诉我!我正在尝试学习角度:)

【问题讨论】:

标签: angular subscribe


【解决方案1】:

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

export class App implements OnInit {

lessons$: Observable<Lessons[]>;

constructor(private lessonsService: lessonsService) {

}

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

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

The Angular documentation.

【讨论】:

    【解决方案2】:

    您可以对来自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 来查找更多信息)。

    【讨论】:

    • 解决了我的问题,谢谢!
    【解决方案3】:

    你的 observable 很冷:

    如果创建了通知的生产者,则可观察对象是冷的 每当观察者订阅 observable 时。例如,一个 可观察到的计时器很冷;每次订阅时,都会有一个新的 计时器已创建。

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

    如果通知的生产者不是 observable,则 observable 是热的 每次观察者订阅 observable 时创建。为了 例如,使用 fromEvent 创建的 observable 很热;元素 生成事件的 DOM 中存在 — 它不是在 观察者已订阅。

    为此,您可以使用share 运算符,但它仍然不能保证您可以进行一次http 调用。 Share 将 multicast 您的 observable,使其在订阅者之间共享,但是一旦 http 调用完成,它将为新订阅者发出新的 http 调用。

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

    延伸阅读:

    Publish and share operators

    【讨论】:

    • 感谢您提及缓存行为。这实际上是我在问自己的问题,但想在这里问它做更多的研究!
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-24
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      • 2017-04-19
      • 2018-03-16
      相关资源
      最近更新 更多