Я хочу иметь возможность кэшировать HTTP-вызов, но также принудительно обновлять кеш. Моя служба выглядит так:
@Injectable()
export class UserService {
private currentUser$: Observable<User>;
constructor(private http: HttpClient) { }
getCurrentUser(force = false): Observable<User> {
if (!this.currentUser$ || force) {
this.currentUser$ = this.http.get<User>(`${environment.API_URL}/profiles/me`)
.pipe(
shareReplay(CACHE_SIZE)
);
}
return this.currentUser$;
}
}
Если я вызываю getCurrentUser(true)
, переменная currentUser$
перезаписывается. Боюсь, это уничтожит всех существующих подписчиков. Это правда? Как их сохранить?
Представьте, что this.currentUser$
указывает на объект в куче.
Ваш метод возвращает копию ссылки на this.currentUser$
. Таким образом, все подписанные наблюдатели будут продолжать слушать их (пока все они не откажутся от подписки и Observable не соберет мусор).
Если вы вызываете метод с помощью "force", this.currentUser$
просто укажет на другой Observable<User>
где-то еще в куче.
Кроме того, будут ли подписчики первого Observable больше не получать обновления, поскольку нет переменной, в которую можно было бы отправлять новые значения?
Это правильные выводы :). Конечно, если вы передадите этот Observable, какой-то другой объект может передать новые значения. Но я полагаю, что это не так. Также нужно быть осторожным с утечками памяти. Всегда откажитесь от подписки на свои Observables. По этому поводу есть много вопросов / ответов.
Я приму ваш ответ, поскольку он отвечает на мой вопрос, но не могли бы вы взглянуть на мое решение и сообщить мне, если у вас возникнут какие-либо проблемы с ним?
У меня недостаточно кредитов, чтобы прокомментировать ваш код ниже :). Но посмотрите на rxjs .take (1), чтобы автоматически отказаться от подписки после того, как вы что-то получили.
Кроме того, разделите эти методы на два отдельных метода. A) Действие: один извлекает пользователей и помещает их в тему и B) для «наблюдателей»: метод, возвращающий переменную-член, такую как userObs$ = currentUser$.asObservable()
.
Спасибо. Я разделил методы. Я также удалил логику отказа от подписки для http-вызова. Судя по всему HttpClient
делает это для тебя
Я собираюсь опубликовать здесь то, что я сделал, на случай, если это поможет кому-то еще. Вместо этого я возвращаю один экземпляр BehaviorSubject
и просто вставляю в него новые значения всякий раз, когда мне нужно «принудительно» получить текущего пользователя. Я также добавил флаг fetchingCurrentUser
, чтобы я не делал несколько вызовов, пока я жду завершения первого вызова API.
Пожалуйста, дайте мне знать, если кто-нибудь увидит какие-либо проблемы с этим или у вас есть идеи, как сделать это очиститель. Спасибо.
@Injectable()
export class UserService {
private currentUser$: BehaviorSubject<User>;
private fetchingCurrentUser: boolean;
constructor(private http: HttpClient) {
this.currentUser$ = new BehaviorSubject(null);
}
getCurrentUser(force = false): Observable<User> {
if (this.currentUser$.value == null || force) {
this.refreshCurrentUser();
}
return this.currentUser$.asObservable();
}
refreshCurrentUser() {
if (!this.fetchingCurrentUser) {
this.fetchingCurrentUser = true;
this.http.get<User>(`${environment.API_URL}/profiles/me`)
.subscribe(x => {
this.currentUser$.next(x);
this.fetchingCurrentUser = false;
});
}
}
Так вы говорите, что у меня в памяти будет два Observable? Один указан переменной, а другой не имеет переменной? Вы также говорите, что, поскольку у первого Observable все еще есть подписчики, он не собирает мусор? Похоже на утечку памяти.