2017-10-05 60 views
0

我仍然对RxJS感到满意,所以这可能是一个简单的问题。RxJS(和Angular):尝试缓存一次性HTTP请求仍然会导致多个请求

目前我正试图懒惰地为某些数据做一个XHR请求,我只需要一次获取一次数据,然后在页面打开时无限期地缓存,并且我想通过试图利用一个AsyncSubject与从Angular的HTTP客户端发出的价值。我至今基本上是这样的:

@Injectable() 
class AuthService { 
    user$ = new BehaviorSubject(null); 
    // do .switchMap() so we reset when the auth'ed user changes 
    extraInfo$ = this.user$.switchMap(() => { 
     return this.http.get('/api/account').share(); 
    }); 

    constructor(http: HttpClient) { } 
    ... 
} 

这几乎工程,因为该请求不发,直到事情订阅extraInfo$.share()应该防止产生额外的请求时我已经在这1个多观察。

但是,如果我取消订阅它并且extraInfo$变冷(因为有0个订阅者),再次订阅它会导致再次发出额外的请求。

现在我很想重写AsyncSubject上的._subscribe()属性,这样我就可以在请求得到它的第一个观察者时运行请求,但这有点太过分了。

+1

我看到'BehaviorSubject' –

回答

0

我发生什么事了最后,以下作品我需要什么:

const lastFetchedInfo = new WeakMap(); 

@Injectable() 
class AuthService { 
    user$ = new BehaviorSubject(null); 
    // do .switchMap() so we reset when the auth'ed user changes 
    extraInfo$ = this.user$.switchMap(user => !user ? Observable.empty() : new Observable((observer) => { 
    if (!lastFetchedInfo.has(user)) { 
     const subject = new BehaviorSubject(null); 
     lastFetchedInfo.set(user, subject.filter(o => o !== null)); 
     this.http.get('/api/account').subscribe(info => subject.next(info)); 
    } 
    const subscription = lastFetchedInfo.get(user); 
    return() => subscription.unsubscribe(); 
    })); 

    constructor(http: HttpClient) { } 
    ... 
} 

我决定用一个BehaviorSubject,而不是AsyncSubject因为我可以扩展到从这里如果刷新数据设置的时间间隔我需要。

1

如果要执行一个请求,然后将结果缓存这个在任何后续的订阅,你可以这样做容易得多:

@Injectable() 
class AuthService { 
    user$ = new BehaviorSubject(null); 

    extraInfo$ = this.user$.switchMap(() => { 
     return this.http.get('/api/account').shareReplay(1); 
    }); 

    constructor(http: HttpClient) { } 
    ... 
} 

使用shareReplay(1)正在修复您有相关的问题share运营商。他们都是多播运营商,但具有不同的属性。您希望操作员具有可重复性而不可重试(请参阅我撰写的关于此主题的文章,以帮助您了解我的意思http://blog.kwintenp.com/multicasting-operators-in-rxjs/)。

请记住,如果您想无限期地缓存某个可观察结果,则需要shareReplay

+0

谢谢!你的文章也有帮助。这有助于摆脱我最终使用的中间'BehaviorSubject'。 – specialkk

+0

但是,当observable再次变热时,仍然存在传递给'.switchMap()'的函数的问题。我认为做'.switchMap(...)。shareReplay(1)'也可以解决这个问题,但这似乎并不奏效。 – specialkk

+0

只需稍微调整一下:'extraInfo $ = this.user $ .switchMapTo(this.http.get('/ api/account')。shareReplay(1))' – Cotton