首页 文章

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

提问于
浏览
2

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

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

Code (onSubmit() from login page button)

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');
  }
);

Console

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

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

4 回答

  • 1

    尝试在 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 找到更多) .

  • 0

    你的观察是冷的:

    如果观察者订阅了observable,则会创建其通知的 生产环境 者,因此observable很冷 . 例如,可观察的计时器是冷的;每次订阅时,都会创建一个新的计时器 .

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

    如果观察者每次订阅观察者时都没有创建通知的制作者,那么观察者就会很热门 . 例如,使用fromEvent创建的observable很热;生成事件的元素存在于DOM中 - 在订阅观察者时不会创建它 .

    为此,您可以使用share运算符,但它仍然不能保证您单个http调用 . 分享将 multicast 您的观察,使其在订阅者之间共享,但一旦http呼叫完成,它将为新订阅者进行新的http呼叫 .

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

    进一步阅读:

    Publish and share operators

  • -1

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

    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.

  • 5

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

    调用Observable的执行并注册Observer处理程序以获取它将发出的通知 .

相关问题