Угловая 2 наблюдаемая подписка дважды выполняет вызов дважды
проблема
Я подписываюсь на HTTPClient.get, наблюдаемый дважды. Однако это означает, что мой вызов выполняется дважды. Почему это?
доказательство
Для каждой подписки() я делаю, я получаю другую строку на странице входа.
Код (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, который обрабатывает все мои функции входа. Он содержит логическую переменную, которая показывает, вошел ли я в систему или нет. Всякий раз, когда я вызываю функцию входа в систему, он подписывается на наблюдаемый httpClient.get, чтобы установить переменную входа в true или false. Но функция входа также возвращает наблюдаемый, на который подписывается. Мне потребовалось некоторое время, чтобы связать двойной запрос с двойной подпиской. Если есть лучший способ отслеживания логина, чем через переменную, дайте мне знать! Я пытаюсь научиться угловатым :)
Ответы
Ответ 1
Вы можете использовать оператор share
для своего результата из HttpClient.get
, например:
var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders })
.pipe(share());
Вам нужно добавить следующий импорт поверх вашего скрипта:
import { share } from 'rxjs/operators';
Оператор share
создает наблюдаемый hot
, то есть разделяемый между подписчиками. Но есть еще кое-что, я бы предложил эту статью углубиться (вы можете, конечно, также погуглить hot vs cold observables
, чтобы найти больше).
Ответ 2
Ваша наблюдаемая холодна:
Наблюдаемое является холодным, если создатель его уведомлений создан всякий раз, когда наблюдатель присоединяется к наблюдаемому. Например, наблюдаемый таймер холодный; каждый раз, когда подписка сделана, новый Таймер создан.
Вам нужно multicast
ваш Observable или, другими словами, чтобы он был горячим:
Наблюдаемое является горячим, если производитель его уведомлений не создается каждый раз, когда наблюдатель подписывается на наблюдаемое. За например, наблюдаемая, созданная с помощью fromEvent, является горячей; элемент который производит события, существует в DOM - он не создается, когда наблюдатель подписан.
Для этого вы можете использовать оператор share, но он по-прежнему не может гарантировать вам один HTTP-вызов. Доля будет multicast
вашей наблюдаемой, делая ее общей для подписчиков, но после завершения http-вызова она сделает новый http-вызов для новых подписчиков.
Если вы хотите использовать режим кэширования (выполнение вызова один раз, а затем предоставление значения каждому подписчику при каждой подписке), вам следует использовать publishReplay().refCount()
.
Дальнейшее чтение:
Опубликуйте и поделитесь операторами
Ответ 3
В дополнение к вышеприведенным ответам, вы можете назначить наблюдаемой вашу службу http
и затем подписаться на получение данных. Например:
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
);
}
}
Угловая документация.
Ответ 4
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html
Вызывает выполнение Observable и регистрирует обработчики Observer для уведомлений, которые он выдает.