我正在编写一个Angular 应用程序,并设置一个系统,在该系统中,NGRX效果将向服务请求数据.

更重要的是,这项服务将做两件事:

  • 判断本地缓存(SQLite)中是否有请求的数据,以及
  • 请联系API获取最新数据

我希望定义此服务的可观察响应,它将只发出API的响应(如果是第一个/本地缓存未命中),或者按该顺序发出本地然后发出API.我已经设想了以下两个场景:

Scenario 1 (API is first/cache miss)

API   ---1
CACHE ---------2
MERGE ---1

Scenario 2 (Cache hit)

API   ---------1
CACHE ---2
MERGE ---2-----1

我正在考虑创建一个主题,然后触发两个调用,并在API响应时完成主题(无论是成功响应还是错误响应).

伪代码:

const subject = new Subject();

this.cache.getData().then(res => subject.next(res)).catch(err => subject.error(err));
this.api.getData().then(res => subject.next(res)).catch(err => subject.error(err)).finally(() => subject.complete());

return subject.asObservable();

但我想知道是否有更干净的解决方案来实现我想要实现的目标?非常感谢您提供的任何意见.

推荐答案

如果我理解正确的话,您想要触发两个调用,A)API,B)缓存.如果A返回,则首先发出结果,但不发出来自B响应.如果B首先返回,则发出该结果,但随后也发出到达时来自A的响应.

从本质上讲,您总是想要来自A的响应.如果B是在A之前收到的,您只想要来自B的响应.

如果是这样的话,你可以定义两个源观测,并将它们定义为merge个.

private apiData$ = defer(() => this.api.getData()).pipe(share());

private cachedData$ = defer(() => this.cache.getData()).pipe(
  filter(existing => !!existing),
  takeUntil(apiData$)
);

data$ = merge(this.cachedData$, this.apiData$);

在这里,我们用defer将您的promise 变成可见的认购.

apiData$使用share(),因为我们最终将有两个订阅,并且我们不希望 for each 订阅分别发出呼叫.

cachedData$使用filter来 suppress 您不需要的排放(when data doesn't exist in cache).

api$发出任何值时,takeUntil被用来完成cachedData$可观测,因此cachedData$apiData$之后永远不会发出

最后,merge用于将两个源合并为单个可观测对象,因此data$将在任何一个源emits 时emits .


这是一张StackBlitz美元.

Typescript相关问答推荐

为什么缩小封闭内部不适用于属性对象,但适用于声明的变量?

泛型函数类型验证

如何使类型只能有来自另一个类型的键,但键可以有一个新值,新键应该抛出一个错误

属性的类型,该属性是类的键,其值是所需类型

当使用`type B = A`时,B的类型显示为A.为什么当`type B = A时显示为`any `|用A代替?

将值添加到具有不同类型的对象的元素

类型脚本`Return;`vs`Return unfined;`

使用Dockerfile运行Vite React应用程序时访问env变量

如何在Type脚本中动态扩展函数的参数类型?

如何将定义模型(在Vue 3.4中)用于输入以外的其他用途

`fetcher.load`是否等同于Get Submit?

确保对象列表在编译时在类型脚本中具有唯一键

判断映射类型内的键值的条件类型

如何使这种一对一关系在旧表上起作用?

创建一个函数,该函数返回一个行为方式与传入函数相同的函数

TypeScrip:使用Cypress测试包含插槽的Vue3组件

TypeScript:方法获胜';t接受较窄类型作为参数

如何在Vuetify 3中导入TypeScript类型?

Typescript泛型-键入对象时保持推理

TS2532:对象可能未定义