Я хочу иметь возможность регулировать мои вызовы API на уровне обслуживания в Angular 10. Все ответы и все примеры, которые я нахожу по использованию rxjs, threadTime описывает сценарии, в которых у нас есть взаимодействие с пользователем, которое запускает регулирование. Как и следующий SO post
Но в моем случае пользователь и компоненты могут запускать один и тот же код службы для загрузки данных из разных мест приложения. Поэтому, когда пользователь переходит на страницу, он запускает вызов, а затем, когда он использует раскрывающийся список, он запускает его снова и т. д.
Это дорогой вызов, но мне все еще нужно поддерживать его относительно свежим. Я хотел бы добиться этого, автоматически обновляя его каждый раз, когда пользователь взаимодействует с ним, но с 10-секундной паузой между каждым обновлением.
Конечная точка API может вызываться с разными значениями. Таким образом, endpoint/1
вернет значение, отличное от endpoint/2
. Это означает, что плоская неосведомленная дроссельная заслонка оставит людей с неправильными данными на 10 секунд, прежде чем им будет разрешено снова вызвать API и обновить состояние просмотра. Что, в свою очередь, усложнило бы код дросселя, который мне пришлось бы создавать повсюду в моем приложении.
Поэтому я подумал, что могу централизовать регулирование в сервисе вместо реализации кода дросселирования, как в примере с сообщениями SO.
Но в этот момент я уперся в стену своими навыками rxjs/angular, и мой разум становится невозможным.
Что я пытался сделать, так это иметь словарь службы, который был проиндексирован на основе параметра, заданного API, который затем смог бы вернуть наблюдаемое, на которое компонент мог подписаться. Это приведет к тому, что у службы будет словарь с опцией состояния для каждого параметра.
Код вырван из некоторого контекста, а вещи переименованы.
class demoState {
triggerSubject$: Subject<void>;
callApi$: Observable<any>;
constructor(callApiObservable: Observable<any>) {
this.triggerSubject$ = new Subject<void>();
this.callApi$ = this.triggerSubject$.pipe(
throttleTime(1000),
switchMap(_ => callApiObservable)
);
}
getRessourceUsingTrigger(): Observable<any> {
// this is the first time I get "stumbed" I don't know a good way to delay the trigger
// of the subject until the end component subscribes.
return of(0).pipe(
// this will trigger before the switchmap is hit and therefore it goes into the void
map(_ => this.triggerSubject$.next(void 0)),
// so this doesn't matter because its underlying observable it never triggered.
switchMap(_ => this.callApi$)
);
}
}
@Injectable({
providedIn: 'root'
})
export class ThrottleService {
private testEndpointTrigger: { [testId: number]: demoState } = {};
constructor() { }
getFromTest(testId: number): Observable<any> {
if(this.testEndpointTrigger[testId] === undefined){
this.testEndpointTrigger[testId] = new demoState(this.GetFromAPI(testId));
}
return this.testEndpointTrigger[testId].getRessourceUsingTrigger();
}
private GetFromAPI(test: number): Observable<any> {
return of(test);
}
}
@Component({
...
})
export class PasswordChangeComponent {
constructor(private throttleService: ThrottleService){}
usingServiceOnUserButtonClick(testId: number){
this.throttleService.getFromTest(testId).subscribe(o => {
console.log('do stuff with the values ', o);
});
}
}
Я надеюсь, что вы могли бы помочь мне понять, что я делаю неправильно, или помочь мне в другом направлении для достижения этой цели.
Изменить после первого комментария bryan60. Я постараюсь сделать шаг назад, немного перефразировать и пойти дальше.
У меня есть вызов API из моего приложения angular, который стоит дорого. Я находится в Service1. Я хочу, чтобы он не вызывался всякий раз, когда пользователь перемещается (компонент вызывает его в oninit) или когда пользователь взаимодействует с пользовательским интерфейсом. Данные используются на разных страницах в приложении и могут использоваться для заполнения выпадающих списков, но они достаточно меняются, чтобы я хотел, чтобы они были относительно свежими (обновляются каждые 10 секунд при взаимодействии).
ApiCall будет генерировать разные результаты в зависимости от ввода пользователя. Поэтому, когда мы переходим на страницу, параметр по умолчанию будет myapi/endpoint/1
, и пользователь может изменить его, и мы вызовем myapi/endpoint/2
. На этом этапе ему нужно игнорировать 10-секундный дроссель, потому что нам нужно получить данные, которых ранее не было в приложении. Если бы пользователь переключился обратно на значение, которое вызвало .../1
, до истечения 10 секунд, нам нужно было бы не вызывать API и показывать некоторые кэшированные данные.
Код, который я показал, является неправильным, не пытался зафиксировать кэшированный аспект уравнения, поскольку я хотел, чтобы дросселирование работало в первую очередь.
Службе необходимо ограничить скорость на основе предоставленных входных данных. Я хочу, чтобы это было в службе, а не в вызывающей стороне, чтобы избежать логики дросселя в каждом компоненте. Моя мысль заключалась в том, что компонент должен иметь доступ к какой-то истории того, какие параметры API были отправлены ранее.
Я посмотрел вокруг rxjs и подумал про себя, что threadtime звучит как хорошее решение для этого, но я не смог найти пример, который не имеет прямого взаимодействия с пользователем для каждого инициированного события. Например, автозаполнение или нажатие кнопок.