【问题标题】:return a shared Observable from a service从服务返回一个共享的 Observable
【发布时间】:2022-11-09 05:20:14
【问题描述】:

如何从服务的方法返回共享的 observable? 我只想接到一个请求并在订阅者之间共享。 如果我将方法分配给公共字段,我可以获得预期的结果,但是我不能将参数传递给它。

这是服务:

@Injectable({
  providedIn: 'root',
})
export class FetchService {
  private entries$ = new Subject<number>();

  constructor() {}

  refreshEntries(id: number) {
    this.entries$.next(id);
  }

  getEntries(id = 0) {
    return this.entries$.pipe(
      startWith(id),
      mergeMap((id) => this.requestEntries(id)),
      shareReplay(1), 
    );
  }

  requestEntries(id: number) {
    console.log('requestEntries');
    return of([1, 2, 3]);
  }
}

和电话:

this.entries$ = this.service.getEntries(0); // called with async pipe in template
this.service.getEntries(0).subscribe((entries) => console.log(entries));

我希望 console.log('requestEntries') 被调用一次。

如果我在没有 getEntries 方法的情况下完成它,它会起作用,但是我可以将 id 传递给调用。 我暂时省略了带有 id 的代码,因为它返回了一些缓存数据。 Stackblitz

【问题讨论】:

    标签: angular typescript rxjs observable rxjs-observables


    【解决方案1】:

    我想这就是你想要的。

    export class FetchService {
      private entries: Observable<number[]>[] = [];
    
      constructor() {}
    
      refreshEntries(id: number) {
        this.entries[id] = of([1, 2, 3]).pipe(shareReplay(1));
      }
    
      getEntries(id = 0) {
        if(!this.entries[id]){
          this.entries[id] = of([1, 2, 3]).pipe(shareReplay(1));
        }
        return this.entries[id];
      }
    }
    

    这只是创建了一个共享的 observable 并将其放入列表中。它会一直返回这个 observable 直到它被刷新。

    【讨论】:

    • 谢谢,这为我指明了正确的方向。
    【解决方案2】:

    您正在尝试构建某种服务缓存,对吗?

    它可以通过 Angular 以不同的方式实现,但谈到您的特定要求,可以通过这种方式完成 (demo)

    type CacheKey = number;
    
    @Injectable({
      providedIn: 'root',
    })
    export class FetchService {
      private cache: Record<CacheKey, Observable<any>> = {};
      constructor() {}
    
      refreshEntries(id: number) {
        this.removeCache(id);
      }
    
      getEntries(id = 0) {
        return this.getOrCreate(id);
      }
    
      requestEntries(id: number) {
        console.log('requestEntries');
        return of([1, 2, 3]);
      }
    
      private getOrCreate(id: CacheKey) {
        if (this.cache[id] === undefined) {
          this.cache[id] = this.requestEntries(id).pipe(shareReplay(1));
        }
    
        return this.cache[id];
      }
    
      private removeCache(id: CacheKey) {
        delete this.cache[id];
      }
    

    【讨论】:

    • 谢谢@RobinDijkhofs 的回答,我得到了与您建议的实现相同的实现。使用地图而不是记录
    猜你喜欢
    • 2017-07-27
    • 2018-01-27
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 2020-10-10
    • 2020-02-12
    • 1970-01-01
    • 2018-06-03
    相关资源
    最近更新 更多