#angular #typescript #rxjs
#angular #машинописный текст #rxjs
Вопрос:
У меня есть Oberservable для получения данных.
Я использую подписку, чтобы вызывать ее через интервал в моем компоненте.
ngOnInit () {
this.subscr = interval (10000).pipe (
startWith (0),
mergeMap (obs => this.myservice.getData ().pipe (catchError (error =>
{
// error
})))).subscribe (resp =>
{
// data
});
}
ngOnDestroy ()
{
this.subscr.unsubscribe ();
}
Мне нравится обновлять данные с помощью действия (например, кнопки).
refreshNow ()
{
this.myservice.getData ().pipe (catchError (error =>
{
// error
})))).subscribe (resp =>
{
// data
});
}
Но мне не нравится иметь getData несколько раз в коде.
Есть ли способ, которым я могу запустить этот.subscr вручную??
Комментарии:
1. Если мой ответ вам помог, можете ли вы пометить его как правильный?
Ответ №1:
Вы можете использовать тему и объединить оба с помощью merge(), что-то вроде:
private readonly triggerRefresh$ = new Subject<void>();
// ....
this.subscr = merge(interval(10000), this.triggerRefresh$)
.pipe (
switchMapTo(this.myservice.getData ()
.pipe(catchError (error => {}))
)
).subscribe (resp => {
// data
});
refreshNow () {
this.triggerRefresh$.next();
}
Комментарии:
1. Могу я спросить, что означает $ в конце переменных?
2.Это просто условные обозначения кода.
iAmAnObservable$
iAmSomeKindOfSubject$$
. Когда переменная заканчивается на это, это означает, что ее можно использовать для создания новых значений.$$
Когда он заканчивается только одним$
, на него можно просто подписаться.
Ответ №2:
Если я правильно понимаю, вы могли бы использовать второй объект, который объединяется с интервалом:
private triggerSubject = new Subject<number>();
ngOnInit() {
merge (this.triggerSubject, interval(10000)).pipe(
// startWith (0), // <---- i don't think this is necessary as you do not use the value anyways..
mergeMap (obs => this.myservice.getData().pipe(
catchError(error => {
// error
})
))).subscribe (resp => {
// data
});
}
refreshNow() {
this.triggerSubject.next(1);
}
Ответ №3:
В других ответах вы можете оказаться в ситуации, когда
- вы ждете 7 секунд
- вы нажимаете на кнопку обновления
- это запускает выборку ваших данных (скажем, за 0,5 с)
- он выдаст только что полученные данные
- он будет ждать оставшиеся 2,5 с (10 с — 7 с — 0,5 с) и выполнить другой запрос
Если вместо этого вы хотели бы:
- возможность обновления в любое время
- дождитесь выполнения запроса
- как только это будет сделано, подождите 10 секунд, затем выполните обновление (снова и снова), пока не будет запущено обновление вручную (в этом случае вы можете начать с первого шага снова)
Тогда вы могли бы сделать следующее:
private DELAY_BETWEEN_REFRESH = 10_000;
public refresh$: Subject<void> = new Subject();
public data$ = refresh$.pipe(
startWith(null),
switchMap(() =>
this.myservice.getData().pipe(
catchError((error) => {
// do not forget about error handling as
// it's important for the stream to end gracefully
// if you do not want to do anything in particular
// simply do `return EMPTY`
}),
repeatWhen((error$) => error$.pipe(delay(DELAY_BETWEEN_REFRESH)))
)
)
);
Самое приятное в этом то, что у вас не будет постоянной скорости обновления, когда вы также запускаете обновление вручную. Обновление вручную всегда будет происходить мгновенно, но автоматическое обновление будет происходить только через 10 секунд после выполнения предыдущего запроса.