【问题标题】:How to create a simple cache using RxJs如何使用 RxJs 创建一个简单的缓存
【发布时间】:2020-10-13 08:35:30
【问题描述】:

我想使用 RxJs 创建一个缓存服务。想法很简单,我有一个类会从服务器初始获取一些数据,还有一个 websocket 会向该服务推送通知(添加/编辑/删除实体)。

下面的代码是一个简化,让我了解如何实现我所需要的。

const source = of(['World', 'test', 'azerty', 'uiop']);
const add$ = new Subject<string>();
const update$ = new Subject<string>();
const delete$ = new Subject<string>();

所以,真正的问题是:如何创建一个高阶 observable 来响应来自 add$、update$ 和 delete$ 的任何更新?

我想要一个变量“cache$”,它是一个由源代码组成的可观察变量,添加更新和删除。并且最初从源流的数据中填充(这将是一个可观察的 http 调用)。

【问题讨论】:

标签: angular rxjs reactive-programming


【解决方案1】:

你可以在这里做

const update$ = merge([
  add$.pipe(map(addItem => items => items.concat([addItem]))),
  delete$.pipe(map(deleteItem => items => items.filter(item => item !== addItem))),
  update$.pipe(map(updateItem => items => items.map(item => /* not very clear how exactly you want to update */))),
])
const cache$ = source.pipe(
  switchMap((startItems) => update$.pipe(scan((prevItems, changerFn) => changerFn(prevItems), startItems))),
  publish(),
);
cache$.connect(); 

【讨论】:

    【解决方案2】:

    好的,我想我找到了解决办法

    import { combineLatest, Observable, of, Subject } from 'rxjs'; 
    import { map, startWith } from 'rxjs/operators';
    
    interface ITestPayload {
      id: number,
      name?: string,
    }
    
    interface ICacheEvent {
      eventType: 'INIT' | 'ADD' | 'EDIT' | 'DELETE',
      payload: ITestPayload,
    }
    
    const source: Observable<Array<ITestPayload>> = of([{id: 1, name: 'World'}, {id: 2, name: 'test'}, {id: 3, name: 'azerty'}]);
    const event$ = new Subject<ICacheEvent>();
    
    let cache$ = combineLatest([
      source,
      event$.pipe(startWith({eventType: 'INIT', payload: null})),
    ]).pipe(
      map(([source, event]) => {
      if (event.eventType === 'ADD'){
          const index = source.map(x => x.id).indexOf(event.payload.id);
    
          if(index === -1) {
            source.push(event.payload);
          }
        }
        else if (event.eventType === 'DELETE'){
          const index = source.map(x => x.id).indexOf(event.payload.id);
    
          if(index >= 0) {
            source.splice(index, 1);
          }
        }
        else if (event.eventType === 'EDIT'){
          const index = source.map(x => x.id).indexOf(event.payload.id);
    
          if(index >= 0) {
            source[index] = event.payload;
          }
        }
    
        return source;
      })
    )
    
    cache$.subscribe(x => console.log(x.map(item => item.name)));
    
    event$.next({eventType: "ADD", payload: {id: 4, name: 'test 4'}})
    event$.next({eventType: "EDIT", payload: {id: 2, name: 'value edited'}});
    event$.next({eventType: "DELETE", payload: {id: 1}});

    另一种解决方案(由我的一位同事提出)

    import { combineLatest, merge,  Observable, of, Subject } from 'rxjs'; 
    import { map, scan,  shareReplay,  startWith } from 'rxjs/operators';
    
    interface ITestPayload {
      id: number,
      name?: string,
    }
    
    interface ICacheEvent {
      eventType: 'INIT' | 'ADD' | 'EDIT' | 'DELETE',
      payload: ITestPayload,
    }
    
    const source: Observable<Array<ITestPayload>> = of([{id: 1, name: 'World'}, {id: 2, name: 'test'}, {id: 3, name: 'azerty'}]);
    const eventSubject$ = new Subject<ICacheEvent>();
    const event$ = eventSubject$.asObservable();
    
    const cache$: Observable<Array<ITestPayload>> = merge(
      source,
      event$,
    ).pipe(
      scan((acc: ITestPayload[], value: ICacheEvent) => {
        console.log('scan');
        if (value.eventType === 'ADD'){
          const index = acc.map(x => x.id).indexOf(value.payload.id);
    
          if(index === -1) {
            acc.push(value.payload);
          }
        }
        else if (value.eventType === 'DELETE'){
          const index = acc.map(x => x.id).indexOf(value.payload.id);
    
          if(index >= 0) {
            acc.splice(index, 1);
          }
        }
        else if (value.eventType === 'EDIT'){
          const index = acc.map(x => x.id).indexOf(value.payload.id);
    
          if(index >= 0) {
            acc[index] = value.payload;
          }
        }
    
        return acc;
      }))
    
    cache$.subscribe(x => console.log('sub 0 :', x.map(item => item.name)));
    
    eventSubject$.next({eventType: "ADD", payload: {id: 4, name: 'test 4'}})
    eventSubject$.next({eventType: "EDIT", payload: {id: 2, name: 'value edited'}});
    eventSubject$.next({eventType: "DELETE", payload: {id: 1}});

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 1970-01-01
      • 2013-06-25
      • 2019-08-31
      • 1970-01-01
      • 2021-03-31
      • 1970-01-01
      相关资源
      最近更新 更多