RxJS - .subscribe()vs .publish().connect()

Cla*_*onK 19 rxjs rxjs5 angular

这主要是RxJs的最佳实践/方法问题,因为我的POC代码有效,但我对RxJs来说是全新的.

问题归结为.subscribe()vs .publish().connect(),因为他们似乎都做同样的事情.

在我的angular2应用程序中,我有一个按钮,它调用一个函数来记录用户,该函数在我的服务中调用一个执行某些服务器端操作的函数,并返回一个URL以将用户重定向到.为了启动请求,我调用.subscribe()以使observable开始生成值.我正在阅读一篇关于"冷与热可观测量"的文章,另一种方法是打电话.publish().connect()而不是.subscribe().两种方法都有任何好处.

<a (click)="logout()">Logout</a>
Run Code Online (Sandbox Code Playgroud)

注销功能如下所示:

logout.component.ts

logout() { this.authService.logout(); }
Run Code Online (Sandbox Code Playgroud)

服务(实际注销)如下所示:

auth.service.ts

logout() : Observable<boolean>  {
        this.http.get(this.location.prepareExternalUrl('api/v1/authentication/logout'))
            .map(this.extractData)
            .catch(this.handleError)
            .do((x: string) => { window.location.href = x; })
            .subscribe();    // Option A - 

        return Observable.of(true);

    }
Run Code Online (Sandbox Code Playgroud)

auth.service.alternative.ts

logout() : Observable<boolean>  {
        this.http.get(this.location.prepareExternalUrl('api/v1/authentication/logout'))
            .map(this.extractData)
            .catch(this.handleError)
            .do((x: string) => { window.location.href = x; })
            .publish()  // Option B - Make connectable observable
            .connect(); // Option B - Cause the connectable observable to subscribe and produce my value       

        return Observable.of(true);
    }
Run Code Online (Sandbox Code Playgroud)

mar*_*tin 23

subscribe()和之间的区别在于.publish().connect()它们订阅了它的源Observable.考虑以下Observable:

let source = Observable.from([1, 2, 3])
Run Code Online (Sandbox Code Playgroud)

此Observable在订阅时向Observer发出所有值.因此,如果我有两个观察者,那么他们按顺序接收所有值:

source.subscribe(val => console.log('obs1', val));
source.subscribe(val => console.log('obs2', val));
Run Code Online (Sandbox Code Playgroud)

这将打印到控制台:

obs1 1
obs1 2
obs1 3
obs2 1
obs2 2
obs2 3
Run Code Online (Sandbox Code Playgroud)

另一方面,呼叫.publish()返回a ConnectableObservable.这个Observable没有source在它的构造函数中订阅它的源代码(在我们的例子中),只保留它的引用.然后你可以订阅多个观察者,没有任何反应.最后,您调用connect()ConnectableObservable订阅source哪个开始发出值.这次已经有两个Observers订阅,所以它逐个向它们发出值:

let connectable = source.publish();
connectable.subscribe(val => console.log('obs1', val));
connectable.subscribe(val => console.log('obs2', val));
connectable.connect();
Run Code Online (Sandbox Code Playgroud)

哪个打印到控制台:

obs1 1
obs2 1
obs1 2
obs2 2
obs1 3
obs2 3
Run Code Online (Sandbox Code Playgroud)

观看现场演示:http://plnkr.co/edit/ySWocRr99m1WXwsOGfjS?p = preview


Bee*_*ice 5

这稍微回避了您的问题,但您可能会发现它有帮助:

我不会从调用http服务的流中返回不同的可观察流,因为这样做会使调用函数无法:

  • 取消流
  • 修改流
  • 判断操作是否成功

相反,我会这样做:

auth.servive.ts

logout() : Observable<string>  {
       return this.http.get(...).map(this.extractData)          
            .catch(this.handleError);
}
Run Code Online (Sandbox Code Playgroud)

现在调用代码可以对结果 url 做任何它想做的事情

logout.component.ts

logout(){
    this.authService.logout().subscribe(
        url => window.location.href = url,
        err => {
            /*todo: handle if error was thrown by authService.handleError*/
        }
    );
}
Run Code Online (Sandbox Code Playgroud)