#angular #rxjs #rxjs5
#angular #rxjs #rxjs5
Вопрос:
В основном это вопрос о наилучшей практике / подходе RxJS, поскольку мой POC-код работает, но я совершенно новичок в RxJS.
Вопрос сводится к .subscribe()
vs .publish().connect()
, поскольку они оба, похоже, делают одно и то же.
В моем приложении angular2 у меня есть кнопка, которая вызывает функцию для выхода пользователя из системы, которая вызывает функцию в моем сервисе, которая выполняет некоторые действия на стороне сервера и возвращает мне URL для перенаправления пользователя. Чтобы инициировать запрос, я вызываю .subscribe()
, чтобы заставить observable начать выдавать значения. Я читал статью о «Холодных и горячих наблюдаемых», и другим подходом было бы вызвать .publish().connect()
вместо .subscribe()
. Есть ли какая-либо выгода в любом подходе.
<a (click)="logout()">Logout</a>
Функция выхода из системы выглядит следующим образом:
выход из системы.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.альтернатива.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()
заключается в том, что они подписываются на свой наблюдаемый источник. Рассмотрим следующее наблюдаемое:
let source = Observable.from([1, 2, 3])
Этот наблюдаемый объект передает все значения наблюдателю сразу после его подписки. Итак, если у меня есть два наблюдателя, то они получают все значения по порядку:
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
. Этот наблюдаемый объект не подписывается на свой исходный код ( 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
Комментарии:
1. Итак, в моем случае, когда я просто хочу, чтобы observable выполнялся в основном немедленно, вызов
.subscribe()
без аргументов, вероятно, является наиболее кратким способом выполнения этого и.publish().connect()
выполняет это обходным путем.2. @ClaytonK В целом да, большую часть времени
subscribe()
достаточно.3. Почему меняется порядок вывода? оба примера показывают, что
obs2
был вторым, кто подписался? Похоже ли это.share()
?4. @Royi Это из-за того, как
Observable.from
работает внутренне. Когда вы подписываетесь, он немедленно начинает выдавать все свои значения. Это означает, что без использования какого-либо планировщика он передаст все свои значения (элементы массива) наблюдателю, который подписался прямо сейчас. Затем снова ко второму наблюдателю. С помощьюConnectableObservable
иconnect()
мы сначала подписываемся на обоих наблюдателей, а затем на источникObservable.from
. Это означает, что он будет выполнять итерацию массива только один раз и передавать каждое значение обоим наблюдателям одновременно.5. таким образом,
publish
эффективно возвращаетSubject
, правильно? и чем это отличается отmulticast
operator?
Ответ №2:
Это немного уводит в сторону от вашего вопроса, но вы можете счесть это полезным:
Я бы не возвращал наблюдаемый поток, отличный от того, который вызывает http
службу, потому что это делает невозможным для вызывающей функции:
- отменить поток
- измените поток
- определите, была ли операция успешной
Вместо этого я бы сделал:
auth.servive.ts
logout() : Observable<string> {
return this.http.get(...).map(this.extractData)
.catch(this.handleError);
}
Теперь вызывающий код может делать все, что захочет, с результирующим URL
выход из системы.component.ts
logout(){
this.authService.logout().subscribe(
url => window.location.href = url,
err => {
/*todo: handle if error was thrown by authService.handleError*/
}
);
}