У меня есть некоторые функции, которые вызывают другие асинхронные функции и возвращают результаты в виде наблюдаемых. Эти функции могут быть подписаны много раз в разных частях моего приложения одновременно.
Я бы хотел предотвратить повторный запуск асинхронной функции, если она все еще "в полете", однако все равно выдает значениевсе подписчики, как только он завершает. Если не в полете, он должен снова вызвать асинхронную функцию.
Есть ли лучший шаблон для этого;я подхожу к этому неправильно?
Я создал тему для сохранения результата и флажок для отслеживания запроса в полете.
inFlight = false;
subject$ = new Subject<any>();
requestsLog = [];
getThing() {
console.log("(getThing) running?", this.inFlight);
return iif(() => this.inFlight, this.subject$, this.fakeAsyncRequest$())
.pipe(
take(1),
tap(date => console.log("(getThing) get value", date)),
tap(date => this.requestsLog.push(date))
);
}
fakeAsyncRequest$ = () => {
return of(new Date().toUTCString()).pipe(
tap(_ => {
console.log("(fakeAsyncRequest) request");
this.requestsLog = []; // Reset things
this.inFlight = true; // Set in flight flag
}),
delay(1500), // Simulate async delay
tap(date => this.subject$.next(date)),
finalize(() => {
console.log("(fakeAsyncRequest) Done");
this.inFlight = false;
})
);
};
smilutateMultiple() {
// Simulate a few calls to this function
this.getThing().subscribe();
this.getThing().subscribe();
this.getThing().subscribe();
setTimeout(() => {
this.getThing().subscribe();
}, 500);
}
Я также пытался использовать BehaviourSubject в комбинациис ExhaustMap, но внутренняя наблюдаемая по-прежнему вызывается для каждой подписки на наблюдаемое.
private subject$ = new BehaviorSubject<any>(false);
public subjectObs$ = this.subject$
.asObservable()
.pipe(exhaustMap(() => this.fakeAsyncRequest()));
fakeAsyncRequest = () => {
console.log("call fake request", new Date().toUTCString());
return this.http
.get("https://www.reddit.com/hot.json")
.pipe(delay(1000));
};
smilutateMultiple() {
// Simulate a few subscriptions to this observable
this.subjectObs$.subscribe(thing => console.log("Thing", thing));
this.subjectObs$.subscribe(thing => console.log("Thing", thing));
// Should be same request.
setTimeout(() => {
this.subjectObs$.subscribe(thing => console.log("Thing", thing));
}, 500);
// Should be new request.
setTimeout(() => {
this.subjectObs$.subscribe(thing => console.log("Thing", thing));
}, 3000);
}