#angular #rxjs
#angular #rxjs
Вопрос:
У меня есть большое приложение, в котором у меня много методов подписки. Если я захочу отказаться от одной из них, то я буду использовать этот код:
getUsersSubscription: Subscription;
ngOnInit() : void {
this.getUsersSubscription = this.userService().subscribe(users => {
...something
})
}
ngOnDestroy() : void {
this.getUsersSubscription.unsubscribe();
}
Проблема в том, что у меня тоже много страниц — компонентов. У меня есть токен jwt, и когда срок его действия истекает, я выхожу из системы пользователя. Проблема в том, что когда я это делаю, некоторые вызовы все еще происходят… Как я могу отписаться от всех вещей в моем приложении после выхода из системы, чтобы мне не нужно было повторять этот шаг для всех моих подписок через все компоненты на моей странице?
Также я использую interceptr для отслеживания истечения срока действия jwt и перенаправляю пользователя на страницу входа в систему.Но есть вызовы, которые все еще выполняются на странице входа, если пользователь что-то нажимает — за несколько секунд до выхода из системы
Комментарии:
1. вы должны использовать intercepter и проверить код состояния. если вы получили 401, то перенаправьте на экран входа в систему.
2. Я использую это. Когда я перенаправляю на страницу входа, некоторые вызовы все еще выполняются, потому что не все подписки отписаны
Ответ №1:
Если вам нужно отказаться от подписки на многие из Observable
, вам следует использовать Subscription
массив:
private subscriptions: Subscription[] = [];
ngOnInit() {
this.subscriptions.push(this.userService.subscribe(users => {
...something
}));
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
Но я думаю, что ваша реальная проблема в том, что у вас может быть больше подписки, чем вам нужно.
Во-первых, вы должны использовать async
канал, когда это возможно. Он обрабатывает подписку и отписку очень хорошо и бесплатно.
Кроме того, имейте в виду, что вам обычно не нужно отписываться от холодных наблюдаемых (например, возвращаемых HttpClient
), потому что при выполнении http-запроса наблюдаемое завершается. Вам нужно отписаться только от холодных наблюдаемых, которые имеют побочные эффекты.
Комментарии:
1. Спасибо за ответ. Как я помещу свою this.getUsersSubscription в этот массив, когда он должен быть инициализирован подписью справа?
2. Извините, я забыл инициализировать массив. Я обновил пример
3. Массив инициализируется перед вводом кода
ngOnInit
.this.userService.subscribe(...)
возвращаетSubscription
объект, который будет помещен в массив.4. Кстати, вам действительно нужно отказаться от подписки на холодные наблюдаемые в приложении Angular, потому что, если есть ожидающий http-запрос, и вы меняете страницу на другой маршрут, запрос не будет отменен, если вы не откажетесь от подписки, которая доступна для
onDestroy
метода component.5. @AliDemirci Спасибо за ваш комментарий. Если вы отмените подписку на холодный observable, http-запрос не будет отменен, но, по крайней мере, ваше приложение проигнорирует результат.
Ответ №2:
В отличие от предыдущих вариантов, вы также можете пойти по следующему маршруту:
Вы можете использовать takeUntil()
оператор, который автоматически отменяет подписку для вас, как только происходит данное событие. Например:
В каком-то компоненте
...
myObservable$ = this.service.foo().pipe(
takeUntil(this.loginService._loggedOutEmitter) <-- (0)
).subscribe()
...
В LoginService
...
_loggedOutEmitter = new Subject<boolean>(); <---- (1)
loggedOut() {
*some logout logic *
this._loggedOutEmitter.next(true); <----------- (2)
}
...
Так же, как и в других решениях, вам пришлось бы импортировать определенную службу и иметь определенную строку, которую вам нужно было бы добавить для каждого наблюдаемого (0), но этот способ должен быть немного более удобным с точки зрения памяти, поскольку вам не нужно было бы отслеживать свои подписки.
Вместо этого у вас есть только еще один наблюдаемый (1), который выдается один раз (2).
Тем не менее, я чувствую, что способ, который вы предложили (очистка в onDestroy [который, кстати, может и, на мой взгляд, также должен выполняться с помощью метода takeUntil ()]), является более чистым.