RxJS -.subscribe() vs .publish(). Connect()
Это, в основном, вопрос с лучшей практикой/подходом RxJs, так как мой код POC работает, но я совершенно новый для RxJs.
Вопрос сводится к .subscribe()
vs .publish().connect()
, так как оба они делают то же самое.
В моем приложении angular2 у меня есть кнопка, которая вызывает функцию для входа пользователя в систему, которая вызывает функцию в моей службе, которая выполняет некоторые действия на стороне сервера и возвращает мне URL-адрес для перенаправления пользователя. Чтобы инициировать запрос, я вызываю .subscribe()
, чтобы заставить наблюдаемое начать создавать значения. Я читал статью "Холодные против горячих наблюдателей", и другой подход заключался бы в вызове .publish().connect()
вместо .subscribe()
. Есть ли какая-либо польза для любого подхода.
<a (click)="logout()">Logout</a>
Функция выхода выглядит следующим образом:
logout.component.ts
logout() { this.authService.logout(); }
И сервис (фактический выход) выглядит следующим образом:
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);
}
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);
}
Ответы
Ответ 1
Разница между subscribe()
и .publish().connect()
заключается в том, что они подписываются на свой источник Observable. Рассмотрим следующее наблюдение:
let source = Observable.from([1, 2, 3])
Этот Observable присваивает все значения правилу Observer, когда он подписывается. Поэтому, если у меня есть два наблюдателя, они получают все значения в порядке:
source.subscribe(val => console.log('obs1', val));
source.subscribe(val => console.log('obs2', val));
Это будет печатать на консоли:
obs1 1
obs1 2
obs1 3
obs2 1
obs2 2
obs2 3
С другой стороны, вызов .publish()
возвращает ConnectableObservable
. Этот Observable не подписывается на источник (source
в нашем примере) в его конструкторе и сохраняет свою ссылку. Тогда вы можете подписаться на несколько наблюдателей, и ничего не происходит. Наконец, вы вызываете connect()
, а ConnectableObservable
подписывается на source
, который начинает испускать значения. На этот раз уже есть два Наблюдателя, которые подписываются, поэтому они выставляют значения для обоих из них по одному:
let connectable = source.publish();
connectable.subscribe(val => console.log('obs1', val));
connectable.subscribe(val => console.log('obs2', val));
connectable.connect();
Что печатает на консоли:
obs1 1
obs2 1
obs1 2
obs2 2
obs1 3
obs2 3
Смотрите демо-версию: http://plnkr.co/edit/ySWocRr99m1WXwsOGfjS?p=preview
Ответ 2
Это немного уклоняется от вашего вопроса, но вы можете счесть его полезным:
Я бы не возвращал другой наблюдаемый поток из того, который вызывает службу http
, потому что это делает невозможным для вызывающей функции:
- отменить поток
- изменить поток
- определить, была ли операция успешной.
Вместо этого я бы сделал:
auth.servive.ts
logout() : Observable<string> {
return this.http.get(...).map(this.extractData)
.catch(this.handleError);
}
Теперь вызывающий код может делать все, что захочет, с результирующим URL-адресом
logout.component.ts
logout(){
this.authService.logout().subscribe(
url => window.location.href = url,
err => {
/*todo: handle if error was thrown by authService.handleError*/
}
);
}